Blogs/Technology

How to Use React Native FS (RNFS): 2026 Guide

Written byMurtuza Kutub
Aug 18, 2026
9 Min Read
How to Use React Native FS (RNFS): 2026 Guide Hero

React Native FS, commonly called RNFS, gives a React Native app access to native file operations on Android and iOS. We can use it to create directories, write and read files, inspect folder contents, copy or delete files, and download remote files to the device.

For most app-owned files, the basic workflow is simple: install RNFS, choose an app-specific directory such as DocumentDirectoryPath, build a file path, and call methods such as writeFile() or readFile(). The examples below show that workflow first, followed by the platform rules that matter in current React Native apps.

React Native FS Quick Answer

npm install react-native-fs
cd ios && bundle exec pod install && cd ..
import RNFS from 'react-native-fs';

const filePath = `${RNFS.DocumentDirectoryPath}/example.txt`;

await RNFS.writeFile(filePath, 'Hello from React Native', 'utf8');
const contents = await RNFS.readFile(filePath, 'utf8');

console.log(contents);

DocumentDirectoryPath is private to the app, persists between launches, and normally requires no storage permission. Use CachesDirectoryPath for files that can be downloaded or generated again, and TemporaryDirectoryPath for short-lived files.

What Is React Native FS?

React Native FS is a native filesystem library with a JavaScript API. Unlike browser storage, it lets the app work with actual files and directories on the device.

MethodPurpose
writeFile()Create or replace a file
readFile()Read a file as text or Base64
mkdir()Create a directory
readDir()List files and subdirectories
exists()Check whether a path exists
copyFile()Copy a file
moveFile()Move or rename a file
unlink()Delete a file or directory
downloadFile()Download a remote file
stat()Read file metadata
writeFile()
Purpose
Create or replace a file
1 of 10

RNFS is useful for offline documents, exported reports, cached downloads, logs, generated images, and other files owned by the app. It does not bypass the Android or iOS storage security model.

Installing React Native FS

Install the original package with npm or Yarn:

npm install react-native-fs

Or install it with Yarn:

yarn add react-native-fs

Modern React Native projects use autolinking, so we should not run the old react-native link command. On iOS, install the CocoaPods dependency and rebuild the app:

cd ios
bundle exec pod install
cd ..

Then import the library:

import RNFS from 'react-native-fs';

A Short Compatibility Note for Current React Native Apps

The original react-native-fs repository has not kept pace with New Architecture-only React Native releases. Existing projects can continue with a tested version, but new projects should verify compatibility with their exact React Native version.

One current option is the maintained @dr.pogodin/react-native-fs fork:

npm install @dr.pogodin/react-native-fs
import * as RNFS from '@dr.pogodin/react-native-fs';

Its main file APIs closely follow RNFS, so the examples in this guide remain applicable. Expo projects can also consider expo-file-system. Whichever package we choose, a clean Android and iOS release build should be part of the compatibility check.

Understanding React Native FS Paths

RNFS exposes directory constants so we do not have to hard-code platform-specific paths.

RNFS pathPlatformBest use
DocumentDirectoryPathAndroid and iOSDurable, app-owned files
CachesDirectoryPathAndroid and iOSRegenerable downloads and cached data
TemporaryDirectoryPathAndroid and iOSShort-lived exports and intermediate files
DownloadDirectoryPathAndroidShared Downloads, subject to Android storage rules
ExternalDirectoryPathAndroidApp-specific files on external storage
MainBundlePathiOSRead-only files packaged with the app
DocumentDirectoryPath
Platform
Android and iOS
Best use
Durable, app-owned files
1 of 6

For ordinary file operations, DocumentDirectoryPath is the safest default:

const notesDirectory = `${RNFS.DocumentDirectoryPath}/notes`;
const notePath = `${notesDirectory}/welcome.txt`;

We should store a relative value such as notes/welcome.txt in a database, not the full iOS sandbox path. The container portion of an iOS path can change, so the current RNFS directory constant should be resolved at runtime.

Writing a File with React Native FS

writeFile() creates a file if it does not exist and replaces its contents if it does. Its arguments are the destination path, content, and encoding.

import RNFS from 'react-native-fs';

export async function saveNote(): Promise<string> {
  const path = `${RNFS.DocumentDirectoryPath}/note.txt`;
  await RNFS.writeFile(path, 'Our first local note', 'utf8');
  return path;
}

Common encodings include utf8 for text and base64 for binary data. Reading or writing a large file as one Base64 string can consume substantial memory, so we should reserve that approach for small, bounded files.

Let’s Build Your React Native App Together!

We build powerful React Native apps that run smoothly on iOS and Android — fast, reliable, and ready to scale.

To add content without replacing the file, use appendFile():

await RNFS.appendFile(filePath, '\nAnother line', 'utf8');

Reading a File with React Native FS

Use readFile() with the same encoding used to write the file:

import RNFS from 'react-native-fs';

export async function readNote(): Promise<string> {
  const path = `${RNFS.DocumentDirectoryPath}/note.txt`;
  return RNFS.readFile(path, 'utf8');
}

File operations can fail because a path is wrong, a file was removed, storage is full, or access has changed. Wrap user-facing operations in try...catch and preserve the native error code for diagnostics:

try {
  const contents = await RNFS.readFile(filePath, 'utf8');
  console.log(contents);
} catch (error) {
  console.error('Unable to read file', error);
}

Creating a Directory

Create a folder with mkdir() before writing files into it:

const reportsDirectory = `${RNFS.DocumentDirectoryPath}/reports`;

if (!(await RNFS.exists(reportsDirectory))) {
  await RNFS.mkdir(reportsDirectory);
}

If several operations may create the same directory simultaneously, an existence check is not a lock. Centralizing file mutations in one storage service helps avoid two tasks changing the same path at once.

Listing Files and Folders

readDir() returns directory entries with names, paths, sizes, timestamps, and helpers that identify files and directories.

const entries = await RNFS.readDir(RNFS.DocumentDirectoryPath);

const files = entries
  .filter(entry => entry.isFile())
  .map(entry => ({
    name: entry.name,
    path: entry.path,
    size: entry.size,
  }));

For a folder containing thousands of files, avoid parsing every file merely to render a screen. A small database index is more efficient for search, sorting, and pagination.

Checking Whether a File Exists

const path = `${RNFS.DocumentDirectoryPath}/settings.json`;

if (await RNFS.exists(path)) {
  const settings = await RNFS.readFile(path, 'utf8');
  console.log(JSON.parse(settings));
}

The file can still change after the check. For critical operations, attempt the read, move, or delete and handle its specific error rather than treating exists() as a guarantee.

Copying, Moving, and Renaming Files

Use copyFile() when both copies should remain:

await RNFS.copyFile(sourcePath, destinationPath);

Use moveFile() to move a file or rename it within a directory:

const oldPath = `${RNFS.DocumentDirectoryPath}/draft.txt`;
const newPath = `${RNFS.DocumentDirectoryPath}/final.txt`;

await RNFS.moveFile(oldPath, newPath);

Both operations run natively, which is more efficient than reading the bytes into JavaScript and writing them again.

Deleting Files and Directories

unlink() deletes a file. It can also remove a directory and its contents, so the target path must be validated carefully.

const path = `${RNFS.DocumentDirectoryPath}/old-report.pdf`;

if (await RNFS.exists(path)) {
  await RNFS.unlink(path);
}

Never join an unchecked filename or user-controlled relative path to a writable directory. Reject path separators and .. segments, and confirm that a cleanup target remains under the directory the app is allowed to manage.

Downloading a File with Progress

downloadFile() downloads directly to a local path and returns a job ID plus a promise. The job ID can be passed to stopDownload() if the user cancels the operation.

import RNFS from 'react-native-fs';

export function downloadReport(
  onProgress: (percentage: number | null) => void,
) {
  const destination = `${RNFS.CachesDirectoryPath}/report.pdf`;

  const task = RNFS.downloadFile({
    fromUrl: 'https://example.com/files/report.pdf',
    toFile: destination,
    progressDivider: 5,
    progress: ({bytesWritten, contentLength}) => {
      onProgress(
        contentLength > 0 ? (bytesWritten / contentLength) * 100 : null,
      );
    },
  });

  const promise = task.promise.then(result => {
    if (result.statusCode < 200 || result.statusCode >= 300) {
      throw new Error(`Download failed with HTTP ${result.statusCode}`);
    }

    return destination;
  });

  return {
    jobId: task.jobId,
    promise,
    cancel: () => RNFS.stopDownload(task.jobId),
  };
}

Some servers do not provide a usable content length, so progress may need an indeterminate state. For important downloads, write to a .partial path first, verify the response and expected checksum, and then move the completed file to its final name.

React Native FS Permissions on Android and iOS

RNFS does not require a general storage permission for every operation. The correct approach depends on who owns the file and where it should appear.

RequirementRecommended approach
Store a private app fileApp-specific path; no broad storage permission
Cache a downloadable fileCachesDirectoryPath; no broad storage permission
Let an Android user choose a documentStorage Access Framework or a document picker
Export a PDF to a user-chosen Android locationA system Save As flow
Select photos or videosThe system photo picker or a maintained media picker
Publish media to the Android galleryMediaStore through a compatible library or native module
Open or export a user-selected iOS documentA document picker or share sheet
Store a private app file
Recommended approach
App-specific path; no broad storage permission
1 of 7

Android Storage Rules

App-specific internal and external directories normally need no storage permission. On current Android versions, requesting WRITE_EXTERNAL_STORAGE does not restore unrestricted shared-storage access, and it provides no additional access for apps targeting Android 11 or later.

Android pickers commonly return a content:// URI. It may represent a local file, cloud document, or media-provider item; it is not guaranteed to be a path RNFS can read directly. Use a URI-aware API or copy the selected item into app-owned storage while access is available.

DownloadDirectoryPath is only a path constant. It does not override scoped storage. When users expect a PDF or document in a public location, a Save As flow is more reliable than requesting broad storage access.

Let’s Build Your React Native App Together!

We build powerful React Native apps that run smoothly on iOS and Android — fast, reliable, and ready to scale.

iOS Storage Rules

iOS keeps each app inside its own sandbox. RNFS can freely manage files in the app’s container, but it cannot provide unrestricted access to files owned by other apps.

Use DocumentDirectoryPath for durable app-owned content, cache storage for reproducible files, and a document picker or share sheet when a user wants to open or export an external document. Cache and temporary files may be purged by the operating system.

Handling Large Files Efficiently

readFile(path, 'base64') loads the entire file into JavaScript and increases its encoded size. That can freeze the interface or exhaust memory when the file is a video, archive, or high-resolution image.

For large files:

  • download, copy, or move them using native file operations;
  • avoid Base64 unless another API specifically requires it;
  • process bounded chunks when the algorithm supports chunking;
  • use a native upload or background-transfer library for long-running transfers;
  • test on a physical, lower-memory device using a release build.

React Native FS Best Practices

  • Choose the directory by lifecycle: documents for durable data, cache for replaceable data, and temporary storage for short-lived work.
  • Store relative file keys instead of permanent absolute iOS paths.
  • Validate filenames before constructing a path from user or server input.
  • Distinguish not-found, permission, low-storage, network, and cancellation failures.
  • Avoid concurrent writes to the same destination; use unique temporary filenames.
  • Validate download status, content type, size, and checksum when integrity matters.
  • Keep passwords and tokens in Keychain- or Keystore-backed secure storage, not ordinary RNFS files.
  • Delete stale cached and partial files according to an age or size policy.

Common React Native FS Errors

SymptomLikely causeWhat to check
ENOENT or “file not found”Incorrect path, missing parent directory, or deleted fileLog the sanitized path and create the parent directory
Permission deniedPath outside app-owned storage or revoked accessUse an app-specific directory or the proper system picker
No space left on deviceDestination volume is fullRemove safe cache files and let the user retry
RNFS cannot read content://...A provider URI was treated as a file pathUse a URI-aware API or copy the content locally
Downloaded file is unusableHTTP error, partial transfer, or unexpected contentCheck status, expected size, MIME type, and checksum
File disappears laterIt was stored in cache or temporary storageMove durable content to the documents directory
ENOENT or “file not found”
Likely cause
Incorrect path, missing parent directory, or deleted file
What to check
Log the sanitized path and create the parent directory
1 of 6

When Not to Use RNFS

RNFS is designed for path-based file operations. It is not the best choice for structured data that needs queries and transactions, credentials requiring secure hardware-backed storage, arbitrary cloud-provider documents, or transfers that must continue reliably after the app is terminated.

In those cases, use a database, secure-storage library, document picker, MediaStore integration, or background-transfer service that matches the requirement.

Frequently Asked Questions

Does React Native FS work on both Android and iOS?

Yes. RNFS exposes a shared API for both platforms, although available directories and storage rules differ. Platform-specific constants should be guarded, and every supported device and OS version should be tested.

Does RNFS need storage permission on Android?

Not for app-specific directories such as the document and cache locations. Shared documents and media require purpose-specific system APIs, including document pickers, Save As flows, the photo picker, or MediaStore.

Where does React Native FS store files?

It stores files at the path we provide. DocumentDirectoryPath points to private, durable app storage, while cache and temporary directory constants point to locations whose contents the operating system may remove.

Can React Native FS read PDF and image files?

RNFS can read their bytes, copy them, move them, delete them, or download them. Rendering a PDF or decoding and displaying an image still requires an appropriate viewer or media component.

Can RNFS access files outside the app?

Only when the platform grants appropriate access. iOS sandboxing and Android scoped storage prevent arbitrary browsing. System pickers are the preferred way to let users select or export files outside app-owned storage.

Is React Native FS suitable for large files?

Native copy, move, and download operations can handle large files. Loading an entire binary into JavaScript as Base64 is memory-intensive, so large transfers should stay native and support progress and cancellation.

Conclusion

React Native FS makes app-owned file handling straightforward: select the correct directory, build a path, and use methods such as writeFile(), readFile(), readDir(), moveFile(), unlink(), and downloadFile().

The most important platform rule is equally simple. Private app directories normally need no broad storage permission; user-owned documents and shared media should go through the system APIs designed for them. With validated paths, deliberate storage locations, and careful handling of downloads and large files, RNFS provides a practical filesystem layer for React Native apps.

Author-Murtuza Kutub
Murtuza Kutub
LinkedIn

A product development and growth expert, helping founders and startups build and grow their products at lightning speed with a track record of success. Apart from work, I love to Network & Travel.

Share this article

Phone

Next for you

8 Best GraphQL Libraries for Node.js in 2025 Cover

Technology

Aug 4, 202613 min read

8 Best GraphQL Libraries for Node.js in 2025

8 Best GraphQL Libraries for Node.js in 2026 Too Long? Read This First - Choose Apollo Server when you need a mature ecosystem, GraphOS integration, plugins, or Apollo Federation. - Choose GraphQL Yoga for a modern, portable server with Fetch API compatibility and built-in support for subscriptions over Server-Sent Events. - Choose Mercurius when your application already uses Fastify and runtime efficiency is a major priority. - Use GraphQL.js when you need the official JavaScript implementati

9 React Native Animation Libraries and Tools Compared Cover

Technology

Aug 4, 202615 min read

9 React Native Animation Libraries and Tools Compared

Too Long? Read This First - Use React Native Reanimated for gesture-driven, interruptible, and performance-sensitive interface animations. - Use the built-in Animated API for simple fades, transforms, and timed sequences without another dependency. - Pair React Native Gesture Handler with Reanimated for swipes, dragging, pinching, rotation, and other touch-driven experiences. - Use Lottie React Native for non-interactive motion graphics supplied by designers. - Choose React Native Skia for cust

9 Critical Practices for Secure Web Application Development Cover

Technology

Aug 4, 202616 min read

9 Critical Practices for Secure Web Application Development

Too Long? Read This First - Define security requirements and model threats before implementation begins. - Treat authentication, account recovery, and MFA as one complete identity system. - Apply server-side authorization to every protected action and object. - Prevent injection with parameterized APIs, structured validation, safe output handling, and restricted outbound requests. - Protect sessions and tokens throughout their complete lifecycle. - Minimise sensitive data and manage encryption