npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-native-file-saver

v2.0.1

Published

<div align="center">

Readme

📁 expo-native-file-saver

Save files natively to Downloads, Documents, Pictures and more — on Android & iOS.

npm version license: MIT platform expo

⚠️ Requires a Development Build — does not work with Expo Go.
See Why not Expo Go? below.


✨ Features

  • 💾 Save files to Downloads, Documents, Pictures, Music, Movies, Cache, or any custom path
  • 🖼️ Supports plain text and base64-encoded data (PDFs, images, ZIPs, etc.)
  • 📂 Optional sub-directory nesting (e.g. MyApp/Reports)
  • 🤖 Android 10+ uses the MediaStore API (no legacy storage permission needed)
  • 🍎 iOS saves into the app sandbox, accessible via the Files app
  • 🔧 Helpers: getDirectoryPath, fileExists, deleteFile
  • 💙 Full TypeScript support

📦 Installation

npx expo install expo-native-file-saver

Then rebuild your native app:

# Android
npx expo run:android

# iOS
npx expo run:ios

🔐 Permissions

Android

Add to your app.json:

{
  "expo": {
    "android": {
      "permissions": [
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "android.permission.READ_EXTERNAL_STORAGE"
      ]
    }
  }
}

On Android 10+ (API 29+), the module uses MediaStore and does not need WRITE_EXTERNAL_STORAGE for Downloads, Pictures, Music, and Movies.

iOS

No extra permissions needed for saving to the app sandbox (Documents, Cache).


🚀 Quick Start

import { saveFile } from 'expo-native-file-saver';
import { Button, Alert } from 'react-native';

export default function App() {
  const handleSave = async () => {
    const result = await saveFile({
      data: 'Hello from expo-native-file-saver!',
      fileName: 'hello.txt',
      mimeType: 'text/plain',
      location: 'downloads',
    });

    Alert.alert('Saved!', result.filePath);
  };

  return <Button title="Save File" onPress={handleSave} />;
}

📖 API

saveFile(options): Promise<SaveFileResult>

Saves a file to the specified location.

import { saveFile } from 'expo-native-file-saver';

// Save plain text to Downloads
const result = await saveFile({
  data: 'Hello World!',
  fileName: 'hello.txt',
  mimeType: 'text/plain',
  location: 'downloads',
});

// Save a base64 PDF to Documents/MyApp/Invoices
const result = await saveFile({
  data: base64PdfString,
  fileName: 'invoice.pdf',
  mimeType: 'application/pdf',
  location: 'documents',
  subDirectory: 'MyApp/Invoices',
  isBase64: true,
});

// Save an image to Pictures
const result = await saveFile({
  data: base64ImageString,
  fileName: 'photo.png',
  mimeType: 'image/png',
  location: 'pictures',
  isBase64: true,
});

console.log(result.filePath); // absolute path where file was saved
console.log(result.success);  // true

Options

| Option | Type | Default | Description | |---|---|---|---| | data | string | required | File content — plain text or base64 string | | fileName | string | required | Filename with extension e.g. "report.pdf" | | mimeType | string | required | MIME type e.g. "application/pdf", "image/png", "text/plain" | | location | StorageLocation | 'downloads' | Where to save the file | | subDirectory | string | '' | Sub-folder within the location e.g. "MyApp/Reports" | | customPath | string | '' | Absolute path (only when location = 'custom') | | isBase64 | boolean | false | Set true if data is base64 encoded | | overwrite | boolean | true | Overwrite if a file with the same name already exists |

Result

{
  success: boolean;
  filePath: string;   // absolute path of the saved file
  message: string;    // human-readable status message
}

getDirectoryPath(options): Promise<string>

Returns the absolute directory path for a given storage location.

import { getDirectoryPath } from 'expo-native-file-saver';

const path = await getDirectoryPath({ location: 'downloads' });
// Android → /storage/emulated/0/Download
// iOS     → /var/mobile/.../Documents

fileExists(filePath: string): Promise<boolean>

import { fileExists } from 'expo-native-file-saver';

const exists = await fileExists('/storage/emulated/0/Download/hello.txt');
console.log(exists); // true or false

deleteFile(filePath: string): Promise<boolean>

import { deleteFile } from 'expo-native-file-saver';

const deleted = await deleteFile('/storage/emulated/0/Download/hello.txt');
console.log(deleted); // true if deleted, false if file didn't exist

📂 Storage Locations

| location | Android | iOS | |---|---|---| | downloads | Public Downloads folder | App Documents dir | | documents | App external Documents | App Documents dir | | pictures | Public Pictures folder | App Documents/Pictures | | music | Public Music folder | App Documents/Music | | movies | Public Movies folder | App Documents/Movies | | cache | App Cache dir | App Cache dir | | custom | Any absolute path | Any absolute path |


💡 Common Use Cases

Download a PDF report

import { saveFile } from 'expo-native-file-saver';

async function downloadReport(base64Pdf: string) {
  const result = await saveFile({
    data: base64Pdf,
    fileName: `report-${Date.now()}.pdf`,
    mimeType: 'application/pdf',
    location: 'downloads',
    isBase64: true,
  });
  return result.filePath;
}

Save a receipt as text

async function saveReceipt(receiptText: string, orderId: string) {
  return await saveFile({
    data: receiptText,
    fileName: `receipt-${orderId}.txt`,
    mimeType: 'text/plain',
    location: 'documents',
    subDirectory: 'MyApp/Receipts',
  });
}

Export JSON data

async function exportData(data: object) {
  return await saveFile({
    data: JSON.stringify(data, null, 2),
    fileName: `export-${new Date().toISOString()}.json`,
    mimeType: 'application/json',
    location: 'downloads',
  });
}

Save captured image

async function saveImage(base64Image: string, name: string) {
  return await saveFile({
    data: base64Image,
    fileName: `${name}.jpg`,
    mimeType: 'image/jpeg',
    location: 'pictures',
    subDirectory: 'MyApp',
    isBase64: true,
  });
}

❓ Why not Expo Go?

Expo Go is a pre-built app with a fixed set of native modules. Adding new native code requires recompiling the native app — which Expo Go doesn't support.

This is the same reason modules like expo-camera and expo-image-picker also require a dev build for advanced features.

Setting up a Development Build is easy:

# Install dev client
npx expo install expo-dev-client

# Build and run
npx expo run:android
npx expo run:ios

Or use EAS Build to build in the cloud:

npm install -g eas-cli
eas build --profile development --platform android

🤝 Contributing

Contributions, issues and feature requests are welcome!

  1. Fork the repo
  2. Create your branch: git checkout -b feat/my-feature
  3. Commit your changes: git commit -m 'feat: add my feature'
  4. Push to the branch: git push origin feat/my-feature
  5. Open a Pull Request

📄 License

MIT © niklashgamerz