---
description: Capacitor file handling guide: read, write, download, and pick files efficiently while avoiding out-of-memory issues on Android and iOS.
title: Capacitor File Handling: The Complete Guide - Capawesome
image: https://capawesome.io/docs/assets/images/social/blog/capacitor-file-handling-guide.png
---

[ Skip to content](#capacitor-file-handling-the-complete-guide) 

[ 🎉 Introducing **Capawesome Platform** — one platform for Live Updates, Native Builds, App Store Publishing, and Insider SDKs.](https://capawesome.io) 

* [  Formbricks ](/docs/plugins/formbricks/)
* [  Geocoder ](/docs/plugins/geocoder/)
* [  Google Sign-In ](/docs/plugins/google-sign-in/)
* [  libSQL ](/docs/plugins/libsql/)
* [  Live Update ](/docs/plugins/live-update/)
* [  Managed Configurations ](/docs/plugins/managed-configurations/)
* [  Media Session ](/docs/plugins/media-session/)
* [  ML Kit ](/docs/plugins/mlkit/)
* [  NFC ](/docs/plugins/nfc/)
* [  OAuth ](/docs/plugins/oauth/)
* [  Pedometer ](/docs/plugins/pedometer/)
* [  Photo Editor ](/docs/plugins/photo-editor/)
* [  PostHog ](/docs/plugins/posthog/)
* [  Printer ](/docs/plugins/printer/)
* [  Purchases ](/docs/plugins/purchases/)
* [  RealtimeKit ](/docs/plugins/realtimekit/)
* [  Screen Orientation ](/docs/plugins/screen-orientation/)
* [  Screenshot ](/docs/plugins/screenshot/)
* [  Secure Preferences ](/docs/plugins/secure-preferences/)
* [  Speech Recognition ](/docs/plugins/speech-recognition/)
* [  Speech Synthesis ](/docs/plugins/speech-synthesis/)
* [  Share Target ](/docs/plugins/share-target/)
* [  Square Mobile Payments ](/docs/plugins/square-mobile-payments/)
* [  SQLite ](/docs/plugins/sqlite/)
* [  Superwall ](/docs/plugins/superwall/)
* [  Torch ](/docs/plugins/torch/)
* [  Wifi ](/docs/plugins/wifi/)
* [  Zip ](/docs/plugins/zip/)
* [  Cloud ](/docs/cloud/)
* [  Live Updates ](/docs/cloud/live-updates/)
* Advanced
* Integrations
* [  Native Builds ](/docs/cloud/native-builds/)
* [  Configuration ](/docs/cloud/native-builds/configuration/)
* [  Environments ](/docs/cloud/native-builds/environments/)
* Guides
* [  Sample Projects ](/docs/cloud/native-builds/sample-projects/)
* [  Troubleshooting ](/docs/cloud/native-builds/troubleshooting/)
* [  Automations ](/docs/cloud/automations/)
* Account
* Organizations
* [  Organization and User Management ](/docs/cloud/organizations/memberships/)
* [  Single Sign-On (SSO) ](/docs/cloud/organizations/sso/)
* [  Teams ](/docs/cloud/organizations/teams/)
* [  Two-Factor Authentication ](/docs/cloud/organizations/two-factor-authentication/)
* [  Integrations ](/docs/cloud/integrations/)
* [  License Keys ](/docs/cloud/license-keys/)
* [  Webhooks ](/docs/cloud/webhooks/)
* [  Pricing ](https://capawesome.io/pricing/)
* [  FAQ ](/docs/cloud/faq/)
* [  Support ](/docs/cloud/support/)
* [  Contributing ](/docs/contributing/)
* [  LLMs ](/docs/llms/)
* [  Insiders ](/docs/insiders/)
* [  License ](https://capawesome.io/legal/eula/)
* [  Support ](/docs/insiders/support/)
* [  FAQ ](/docs/insiders/faq/)
* [  Blog ](/blog/)
* Categories

* [  Conclusion ](#conclusion)

* Related links

# Capacitor File Handling: The Complete Guide[¶](#capacitor-file-handling-the-complete-guide "Permanent link")

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.

[ ![Build and deploy your Capacitor app with Capawesome Cloud](../../assets/external/cloud.capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.69628c3f.png) ](/) 

## Problem[¶](#problem "Permanent link")

`[](#%5F%5Fcodelineno-0-1)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[¶](#best-practices "Permanent link")

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[¶](#read-a-file "Permanent link")

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) method of the Capacitor Filesystem plugin. Instead, use the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch%5FAPI/Using%5FFetch) in combination with the [convertFileSrc(...)](https://capacitorjs.com/docs/basics/utilities#capacitorconvertfilesrc) method to load the file as a blob:

`[](#%5F%5Fcodelineno-1-1)import { Camera, CameraResultType } from "@capacitor/camera";
[](#%5F%5Fcodelineno-1-2)
[](#%5F%5Fcodelineno-1-3)const getPhotoAsBlob = async () => {
[](#%5F%5Fcodelineno-1-4)  // 1. Pick a photo
[](#%5F%5Fcodelineno-1-5)  const photo = await Camera.getPhoto({
[](#%5F%5Fcodelineno-1-6)    resultType: CameraResultType.Uri,
[](#%5F%5Fcodelineno-1-7)  });
[](#%5F%5Fcodelineno-1-8)  // 2. Convert the path to a webPath
[](#%5F%5Fcodelineno-1-9)  const webPath = Capacitor.convertFileSrc(photo.path);
[](#%5F%5Fcodelineno-1-10)  // 3. Load the photo as a blob
[](#%5F%5Fcodelineno-1-11)  const response = await fetch(webPath);
[](#%5F%5Fcodelineno-1-12)  return response.blob();
[](#%5F%5Fcodelineno-1-13)};
`

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](#fn:1)

### Write a file[¶](#write-a-file "Permanent link")

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) 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) plugin:

`[](#%5F%5Fcodelineno-2-1)import { Directory } from "@capacitor/filesystem";
[](#%5F%5Fcodelineno-2-2)import write_blob from "capacitor-blob-writer";
[](#%5F%5Fcodelineno-2-3)
[](#%5F%5Fcodelineno-2-4)const writeBlob = async () => {
[](#%5F%5Fcodelineno-2-5)  const blob = new Blob(["Hello world!"], { type: "text/plain" });
[](#%5F%5Fcodelineno-2-6)  await write_blob({
[](#%5F%5Fcodelineno-2-7)    path: "notes/hello.txt",
[](#%5F%5Fcodelineno-2-8)    directory: Directory.Data,
[](#%5F%5Fcodelineno-2-9)    blob: blob,
[](#%5F%5Fcodelineno-2-10)  });
[](#%5F%5Fcodelineno-2-11)};
`

Another option is to use the [Capacitor File Chunk](https://github.com/qrclip/capacitor-file-chunk) 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[¶](#display-a-file "Permanent link")

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) method and then set it as the `src` attribute of an HTML element:

`[](#%5F%5Fcodelineno-3-1)import { Camera, CameraResultType } from "@capacitor/camera";
[](#%5F%5Fcodelineno-3-2)
[](#%5F%5Fcodelineno-3-3)const displayPhoto = async () => {
[](#%5F%5Fcodelineno-3-4)  // 1. Pick a photo
[](#%5F%5Fcodelineno-3-5)  const photo = await Camera.getPhoto({
[](#%5F%5Fcodelineno-3-6)    resultType: CameraResultType.Uri,
[](#%5F%5Fcodelineno-3-7)  });
[](#%5F%5Fcodelineno-3-8)  // 2. Convert the path to a webPath
[](#%5F%5Fcodelineno-3-9)  const webPath = Capacitor.convertFileSrc(photo.path);
[](#%5F%5Fcodelineno-3-10)  // 3. Display the photo
[](#%5F%5Fcodelineno-3-11)  document.getElementById("savedPhoto").src = webPath;
[](#%5F%5Fcodelineno-3-12)};
`

`[](#%5F%5Fcodelineno-4-1)<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[¶](#open-a-file "Permanent link")

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](/docs/plugins/file-opener/) plugin:

`[](#%5F%5Fcodelineno-5-1)import { FileOpener } from "@capawesome-team/capacitor-file-opener";
[](#%5F%5Fcodelineno-5-2)
[](#%5F%5Fcodelineno-5-3)const openFile = async () => {
[](#%5F%5Fcodelineno-5-4)  await FileOpener.openFile({
[](#%5F%5Fcodelineno-5-5)    path: "file:///path/to/device/file",
[](#%5F%5Fcodelineno-5-6)  });
[](#%5F%5Fcodelineno-5-7)};
`

Tip

On iOS, the [UIDocumentInteractionController](https://developer.apple.com/documentation/uikit/uidocumentinteractioncontroller) 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) plugin to share the file with another app.

### Pick a file[¶](#pick-a-file "Permanent link")

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

`[](#%5F%5Fcodelineno-9-1)import { FilePicker } from "@capawesome/capacitor-file-picker";
[](#%5F%5Fcodelineno-9-2)
[](#%5F%5Fcodelineno-9-3)const pickFile = async () => {
[](#%5F%5Fcodelineno-9-4)  const result = await FilePicker.pickFiles();
[](#%5F%5Fcodelineno-9-5)  return result.files[0].path;
[](#%5F%5Fcodelineno-9-6)};
`

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.

### Upload a file[¶](#upload-a-file "Permanent link")

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%5FAPI/Using%5FFetch):

`[](#%5F%5Fcodelineno-11-1)import { Camera, CameraResultType } from "@capacitor/camera";
[](#%5F%5Fcodelineno-11-2)import { Capacitor } from "@capacitor/core";
[](#%5F%5Fcodelineno-11-3)
[](#%5F%5Fcodelineno-11-4)const uploadFile = async (path: string) => {
[](#%5F%5Fcodelineno-11-5)  // 1. Pick a photo
[](#%5F%5Fcodelineno-11-6)  const photo = await Camera.getPhoto({
[](#%5F%5Fcodelineno-11-7)    resultType: CameraResultType.Uri,
[](#%5F%5Fcodelineno-11-8)  });
[](#%5F%5Fcodelineno-11-9)  // 2. Load the photo as a blob
[](#%5F%5Fcodelineno-11-10)  const response = await fetch(photo.webPath);
[](#%5F%5Fcodelineno-11-11)  const blob = response.blob();
[](#%5F%5Fcodelineno-11-12)  // 3. Upload the file
[](#%5F%5Fcodelineno-11-13)  const formData = new FormData();
[](#%5F%5Fcodelineno-11-14)  formData.append("file", blob, "file.jpg");
[](#%5F%5Fcodelineno-11-15)  await fetch("https://example.tld/upload", {
[](#%5F%5Fcodelineno-11-16)    method: "POST",
[](#%5F%5Fcodelineno-11-17)    body: formData,
[](#%5F%5Fcodelineno-11-18)  });
[](#%5F%5Fcodelineno-11-19)};
`

### Download a file[¶](#download-a-file "Permanent link")

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) plugin to download the file directly to the file system:

`[](#%5F%5Fcodelineno-12-1)import { Filesystem, Directory } from "@capacitor/filesystem";
[](#%5F%5Fcodelineno-12-2)
[](#%5F%5Fcodelineno-12-3)const downloadFile = async () => {
[](#%5F%5Fcodelineno-12-4)  await Filesystem.downloadfile({
[](#%5F%5Fcodelineno-12-5)    path: "image.png",
[](#%5F%5Fcodelineno-12-6)    url: "https://example.tld/image.png",
[](#%5F%5Fcodelineno-12-7)  });
[](#%5F%5Fcodelineno-12-8)};
`

## Conclusion[¶](#conclusion "Permanent link")

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) [↩](#fnref:1 "Jump back to footnote 1 in the text")

May 7, 2026 

 Back to top 