nexa
ExploreServicesAboutTeamFAQBlogContact
GitHubStart a project
Blog · Engineering

Why we wrote our own file-system wrapper for React Native

Three of our apps needed to save, read and export files. Each one did it slightly differently, so we pulled the shared bits into a small library.

Ethan

Tech Lead · Mobile & Web

September 18, 20263 min read

On this page

  1. The problem: copies that drift
  2. Step by step
  3. The API in practice
  4. What we left out
  5. Testing on real phones

Every utility app we ship eventually touches the disk. A scanner saves an image, a recorder writes audio, a calculator exports a PDF. For years each project carried its own helper file for this, copied from the last project and patched along the way. This is the story of replacing those copies with one small library, written as a walkthrough you can follow in your own codebase.

What you will learn
  • How to audit what your file helpers are actually used for
  • The four calls that covered almost everything in our apps
  • What we deliberately left out, and why

The problem: copies that drift

Copy-paste helpers work until they don't. A bug fixed in one app stayed broken in two others. One helper trimmed trailing slashes, another did not. One wrote to the cache folder by default, another to documents. The code looked the same at a glance, which made the differences harder to spot.

Before: a copy per app

  1. Scanner app with its own helper, first version
  2. Recorder app with its own helper, patched
  3. Calculator app with its own helper, forked

After: one shared library

  1. Scanner app uses react-native-simple-fs
  2. Recorder app uses react-native-simple-fs
  3. Calculator app uses react-native-simple-fs
The same job, done three slightly different ways, became one dependency.

Step by step

  1. List every call site

    Search each app for its file helper and write down what every call does in plain words. Not what the helper can do, only what the app uses it for.

  2. Group by intent

    Our list collapsed into five intents: write a file, read it back, list a folder, delete something, and know where documents live versus cache.

  3. Design the smallest API that covers the list

    One function per intent, plain string paths, directory constants exposed up front.

  4. Migrate one app at a time

    Each migration was mostly deletion: the old helper went away and a handful of imports changed.

The API in practice

import SimpleFS from "react-native-simple-fs";

const path = `${SimpleFS.DocumentDir}/notes.txt`;

await SimpleFS.writeFile(path, "Hello, world!");
const content = await SimpleFS.readFile(path, "utf8");
const files = await SimpleFS.listFiles(SimpleFS.DocumentDir);
CallWhat it is for
DocumentDirWhere files the user cares about should live. Survives app updates.
writeFileWrite a string to a path. Paths are plain strings, easy to log.
readFileRead it back with an explicit encoding, so nothing is guessed.
listFilesSee what is in a folder, for history screens and cleanup.
  1. App screensScanning, recording and export flows
    ScanRecordExport
  2. react-native-simple-fsOne typed API with the same defaults in every app
    writeFilereadFilelistFiles
  3. Platform file APIsiOS and Android, reached through the native layer
    iOSAndroid
  4. Device storageSandboxed per app
    DocumentsCache
Where the library sits. App code never calls platform file APIs directly.

What we left out

Streaming large files, watching folders and zip support all came up in the first week. They are useful, but they are also where file libraries become hard to reason about. Our rule: a feature gets in only if at least two of our own apps need it today.

If you need more

Nothing stops a heavier file-system package from living alongside this one. Use the small API for everyday reads and writes, and reach for the big one only where it earns its weight.

Testing on real phones

Simulators lie about file systems more than about almost anything else. Before each release we run a short manual pass on an older Android phone and a recent iPhone.

  • Write and read back a file with non-ASCII charactersEncodings are where helpers usually break first.
  • Write into a folder that does not exist yet
  • List an empty folder and one with many files
  • Delete a file that is already goneShould be a no-op, not a crash.
  • Kill the app mid-write and check nothing is left half written
If a helper needs a README longer than its source, it is probably doing too much.

The library is on npm and the source is public. If you find a gap, the issues page is the best place to tell us. If the honest answer is that your use case needs a larger library, we will say so.

Mentioned in this post

react-native-simple-fs

Case study

Work with us

Need an app like react-native-simple-fs built?

Our services

Keep reading

All posts
  • AI can design an app now. Are designers redundant?
    Read post

    Design

    AI can design an app now. Are designers redundant?

    AI makes the first draft of a screen cheap. That shifts design work to what matters most: understanding users and choosing what is right for them.

    Tina· Oct 10, 20266 min read
  • AI in software development: turn change into an advantage
    Read post

    Engineering

    AI in software development: turn change into an advantage

    AI does not replace technical thinking. With the right process, it frees teams to focus on the decisions that make products better.

    Ethan· Oct 9, 20264 min read
  • Adding AI to an app without a surprise bill
    Read post

    Engineering

    Adding AI to an app without a surprise bill

    Most of the cost of an AI feature is decided before the first request. Model routing, caching, context size and hard limits, in order of impact.

    Ethan· Oct 7, 20267 min read
nexa
ExploreServicesAboutTeamFAQBlogContact

© 2026 Nexa Tech. All rights reserved.

Web · Mobile · Open source