---
title: "Capacitor File Handling: The Complete Guide"
description: "Capacitor file handling guide: read, write, download, and pick files efficiently while avoiding out-of-memory issues on Android and iOS."
date:
  created: 2024-02-21
  updated: 2026-07-14
authors:
  - robingenz
categories:
  - Capacitor
  - Guides
  - SDKs
links:
  - Capacitor File Compressor: sdks/capacitor/file-compressor.md
  - Capacitor File Opener: sdks/capacitor/file-opener.md
  - Capacitor File Picker: sdks/capacitor/file-picker.md
faq: true
search:
  boost: 2
---

# Capacitor File Handling: The Complete Guide

Handling files in Capacitor can be a crucial part of your app.
Whether you want to read, write or share a file, it is essential to understand the best practices in file handling to avoid potential out of memory (OOM) issues.
In this guide, we will explore what you need to consider when dealing with files on Android and iOS and how to ensure efficient and reliable file management.

<!-- more -->

<div class="capawesome-z29o10a">
  <a href="/" target="_blank">
    <img alt="Build and deploy your Capacitor app with Capawesome Cloud" src="https://capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
  </a>
</div>

## Problem

```
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 268431376 byte allocation with 100663296 free bytes and 123MB until OOM, target footprint 239514824, growth limit 268435456
```

This and similar errors are often caused by inefficient file handling.
The most common mistake is to load a file into the WebView as a base64 string or data URL.
This can quickly lead to OOM errors, especially when dealing with large files.

## Best Practices

Capacitor provides powerful capabilities for working with files in a cross-platform app environment.
The following best practices will help you to avoid potential pitfalls and ensure efficient and reliable file management.

### Read a file

When reading a file, you should make sure that the file is not loaded into the WebView as a base64 string or data URL.
So forget about the [`readFile(...)`](https://capacitorjs.com/docs/apis/filesystem#readfile){:target="_blank"} method of the Capacitor Filesystem plugin.
Instead, use the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch){:target="_blank"} in combination with the [`convertFileSrc(...)`](https://capacitorjs.com/docs/basics/utilities#capacitorconvertfilesrc){:target="_blank"} method to load the file as a blob:

```ts
import { Camera, CameraResultType } from "@capacitor/camera";

const getPhotoAsBlob = async () => {
  // 1. Pick a photo
  const photo = await Camera.getPhoto({
    resultType: CameraResultType.Uri,
  });
  // 2. Convert the path to a webPath
  const webPath = Capacitor.convertFileSrc(photo.path);
  // 3. Load the photo as a blob
  const response = await fetch(webPath);
  return response.blob();
};
```

A blob is a file-like object that can be used for further operations.
As soon as the in-memory space for blobs is getting full, the blob system will automatically uses the disk.[^1]

### Write a file

If you do not load any files into the WebView, writing a file via the WebView is usually not necessary.
Nevertheless, if you want to write a file via the WebView, you should make sure that the file is not written as a base64 string or data URL.
So again, forget about the [`writeFile(...)`](https://capacitorjs.com/docs/apis/filesystem#writefile){:target="_blank"} method of the Capacitor Filesystem plugin.
Instead, use a Capacitor plugin that supports writing a file as a blob.
For example, you can use the [Capacitor Blob Writer](https://github.com/diachedelic/capacitor-blob-writer){:target="_blank"} plugin:

```ts
import { Directory } from "@capacitor/filesystem";
import write_blob from "capacitor-blob-writer";

const writeBlob = async () => {
  const blob = new Blob(["Hello world!"], { type: "text/plain" });
  await write_blob({
    path: "notes/hello.txt",
    directory: Directory.Data,
    blob: blob,
  });
};
```

Another option is to use the [Capacitor File Chunk](https://github.com/qrclip/capacitor-file-chunk){:target="_blank"} plugin.

!!! warning

    Writing a file as a blob via the WebView needs a local HTTP server to be started, which is associated with **potential security risks**.
    You can find more information in the documentation of the respective plugin.

You can now use the path to the selected file to open, share or upload the file with another plugin.

### Display a file

To display a file, you can simply convert the native file path to a webPath using the [`convertFileSrc(...)`](https://capacitorjs.com/docs/basics/utilities#capacitorconvertfilesrc){:target="_blank"} method and then set it as the `src` attribute of an HTML element:

```ts
import { Camera, CameraResultType } from "@capacitor/camera";

const displayPhoto = async () => {
  // 1. Pick a photo
  const photo = await Camera.getPhoto({
    resultType: CameraResultType.Uri,
  });
  // 2. Convert the path to a webPath
  const webPath = Capacitor.convertFileSrc(photo.path);
  // 3. Display the photo
  document.getElementById("savedPhoto").src = webPath;
};
```

```html
<img id="savedPhoto" />
```

This way, you don't have to load the file as a base64 string or data URL into the WebView and can avoid potential OOM issues.

### Open a file

At some point, you may want to open a file with another app.
For example, you may want to open a PDF file with a PDF viewer app.
To do this, you can use the [Capacitor File Opener plugin](../../sdks/capacitor/file-opener.md):

```ts
import { FileOpener } from "@capawesome-team/capacitor-file-opener";

const openFile = async () => {
  await FileOpener.openFile({
    path: "file:///path/to/device/file",
  });
};
```

!!! tip

    On iOS, the [UIDocumentInteractionController](https://developer.apple.com/documentation/uikit/uidocumentinteractioncontroller){:target="_blank"} is used to preview and open files.
    If you would rather give the user the option to choose the app to open the file with, you can just use the [Capacitor Share](https://capacitorjs.com/docs/apis/share){:target="_blank"} plugin to share the file with another app.

    For PDFs specifically, if you'd rather render the document inside your app instead of handing it off to another app, the [Capacitor PDF Viewer plugin](../../sdks/capacitor/pdf-viewer.md) displays PDF files directly in your Capacitor app.

<!--
### Edit a file

Many apps offer the possibility to edit a file with a third-party app.
For example, your users may want to edit a PDF file with a PDF editor app.
You can implement this in Capacitor as follows:

```ts
import { App, Capacitor } from '@capacitor/core';
import { FileOpener } from '@capacitor-team/capacitor-file-opener';
import { Share } from '@capacitor/share';

const editFile = async (path: string) => {
  // Open the file with a third-party app
  if (Capacitor.getPlatform() === 'ios') {
    const { canceled } = await Share.share({
      url: path,
    });
    if (canceled) {
      return;
    }
  } else if (Capacitor.getPlatform() === 'android') {
    await FileOpener.openFile({
      path: path,
    });
  } else {
    return;
  }
  // Wait for the user to go back to your app
  await new Promise(resolve => {
    App.addListener('resume', () => {
      resolve();
    });
  });
};
```

It is important that the third-party app does not create a new file when saving the changes, but overwrites the original file.
This way, you can be sure that the file is still at the same location after the user has finished editing it.
Many third-party apps also offer special APIs that can be used to edit files.
-->

<!--
### Share a file

Sharing files with other apps or users is a common requirement in many applications.
You only have to distinguish between sending a file to another app and receiving a file from another app.

#### Send a file to another app

To send a file to another app, you can simply use the [Capacitor Share](https://capacitorjs.com/docs/apis/share){:target="_blank"} plugin:

```ts
import { Share } from '@capacitor/share';

const shareFile = async (path: string) => {
  await Share.share({
    url: path,
  });
};
```

This way, you can share a file with any other app that supports the file type.

#### Receive a file from another app

To receive a file from another app, you need listen to the `appUrlOpen` event of the [Capacitor App](https://capacitorjs.com/docs/apis/app){:target="_blank"} plugin:

```ts
App.addListener('appUrlOpen', event => {
  if (event.url.startsWith('file://')) {
    console.log(event.url);
  }
});
```
-->

### Pick a file

When picking a file, it is recommended to use the [Capacitor File Picker plugin](../../sdks/capacitor/file-picker.md).
This way, you can just get the path to the selected file without the need to load the file into the WebView:

```ts
import { FilePicker } from "@capawesome/capacitor-file-picker";

const pickFile = async () => {
  const result = await FilePicker.pickFiles();
  return result.files[0].path;
};
```

Of course, you can also use the HTML `<input type="file">` element to pick a file.
However, you then have the problem that you first have to write the file to the file system before you can process it with another plugin.

<!--
### Compress a file

Before uploading a file to the server, it often makes sense to compress it first.
This can significantly reduce the file size and thus the upload time.
To compress a file, you can use the [Capacitor File Compressor plugin](../../sdks/capacitor/file-compressor.md):

```ts
import { FileCompressor } from '@capawesome-team/capacitor-file-compressor';

const compressImage = async () => {
  const { path } = await FileCompressor.compressImage({
    mimeType: 'image/jpeg',
    path: 'content://com.android.providers.downloads.documents/document/msf%3A1000000485',
    quality: 0.7,
  });
  return path;
};
```

The example above shows how to compress an image.
Using the `quality` option, you can specify the quality of the resulting image, expressed as a value from `0.0` to `1.0`.
The higher the value, the higher the quality and the larger the file size.
In one of the next versions, it will also be possible to compress other file types and entire folders.
-->

### Upload a file

Uploading a file is actually quite simple and does not require any plugins. We just need to [read the file](#read-a-file) as a blob and then upload it via the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch){:target="_blank"}:

```ts
import { Camera, CameraResultType } from "@capacitor/camera";
import { Capacitor } from "@capacitor/core";

const uploadFile = async (path: string) => {
  // 1. Pick a photo
  const photo = await Camera.getPhoto({
    resultType: CameraResultType.Uri,
  });
  // 2. Load the photo as a blob
  const response = await fetch(photo.webPath);
  const blob = response.blob();
  // 3. Upload the file
  const formData = new FormData();
  formData.append("file", blob, "file.jpg");
  await fetch("https://example.tld/upload", {
    method: "POST",
    body: formData,
  });
};
```

If your backend is Firebase Cloud Storage specifically, skip the manual `fetch`/`FormData` approach above and use the [Capacitor Firebase Cloud Storage plugin](./capacitor-firebase-cloud-storage-guide.md) instead — it uploads directly from a native file `uri` on Android/iOS, no blob conversion needed.

### Download a file

When downloading a file, you should make sure that the file is not loaded into the WebView as a base64 string or data URL.
It is best to use the [Capacitor Filesystem](https://capacitorjs.com/docs/apis/filesystem){:target="_blank"} plugin to download the file directly to the file system:

```ts
import { Filesystem, Directory } from "@capacitor/filesystem";

const downloadFile = async () => {
  await Filesystem.downloadfile({
    path: "image.png",
    url: "https://example.tld/image.png",
  });
};
```

<!-- ## Utilities

### Convert a native path -->

## FAQ

### How do I generate a PDF file?

Reports, receipts, and invoices are a common reason to create files on the fly. The [Capacitor PDF Generator plugin](../../sdks/capacitor/pdf-generator.md) generates paginated PDF files from HTML content or a URL, with selectable page sizes and orientation on Android and iOS. You render the document as HTML, hand it to the plugin, and get back a file path you can then [open](#open-a-file) with the approach above.

### How do I remove GPS data from a photo before uploading it?

Photos taken with a camera often embed EXIF metadata such as GPS coordinates and device details — information you usually don't want to leak when a user uploads an image. The [Capacitor Exif plugin](../../sdks/capacitor/exif.md) losslessly reads, writes, and strips EXIF metadata (including from HEIC files), so you can clear location data before the [upload step](#upload-a-file).

### How do I crop or resize an image?

For headless image transforms without a UI, the [Capacitor Photo Manipulator plugin](../../sdks/capacitor/photo-manipulator.md) handles crop, resize, rotate, flip, and format conversion — including HEIC to JPEG. It pairs well with the upload flow when you need a thumbnail or a fixed-size avatar.

## Conclusion

In this guide, we have explored the best practices for handling files in Capacitor.
By following these best practices, you can avoid potential pitfalls and ensure efficient and reliable file management.
If you have any questions or feedback, feel free to reach out to us.

[^1]: [Chrome's Blob Storage System Design](https://chromium.googlesource.com/chromium/src/+/HEAD/storage/browser/blob/README.md){:target="_blank"}
