
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Simplified access to browser's Origin Private File System (OPFS) for persistent client-side file storage.
Reference: MDN: Origin Private File System
OPFS.js is a JavaScript library that simplifies file and directory interactions with the browser's Origin Private File System (OPFS). OPFS provides fast, persistent, and secure file storage directly in the browser.
This library is created to reduce boilerplate and complexity around OPFS API usage by offering an easy-to-use, promise-based interface.
Compared to traditional browser storage options like IndexedDB, OPFS is significantly faster and more efficient for binary data and file operations:
OPFS is designed for use cases where you need truly persistent, local file storage within the browser—ideal for applications like:
Unlike localStorage, sessionStorage, or IndexedDB, OPFS persists even across browser restarts and supports advanced features like true file handles, stream APIs, and large binary file support—making it ideal for storing and accessing files like images, audio, documents, or any data-heavy content.
Web Worker compatible — This library fully supports usage inside Web Workers (without relying on FileSystemSyncAccessHandle), enabling efficient background file operations for modern web applications.
OPFS data is stored in a persistent quota-managed sandbox that survives page reloads and browser restarts. this library wraps navigator.storage.getDirectory() correctly, which gives access to this persistent storage.
OPFS.js makes this power usable with minimal code.
readFile, writeFile, appendFile, deleteFile, renameFile, copyFile, fileExistsreadDir, listFiles, listDirectories, readAllFiles, readAllDirectories, createDirectory, deleteDirectory, renameDirectory, dirExistsresolvePath, joinPath, splitPath, getParentDirectoryensurePermission, getFileMeta, isReadable, isWritablestreamFile, writeStream, readFileChunkimportFile, exportFilegetQuota, clearOPFSdebugTree.toBlob(), .toText(), .toJSON(), .toArrayBuffer(), .toDataURL()localStorage, sessionStorage, and IndexedDB| Feature | localStorage | IndexedDB | OPFS (via OPFS.js) |
|---|---|---|---|
| Capacity | ~5MB | GBs (slower) | GBs (fast) |
| Binary Support | ❌ | ✅ (but complex) | ✅ (stream + buffer) |
| File Hierarchy | ❌ | ❌ | ✅ |
| Stream API | ❌ | ❌ | ✅ |
| Random Access | ❌ | Limited | ✅ |
| Persist after restart | ✅ | ✅ | ✅ |
| Simplicity | ✅ | ❌ | ✅ |
| Browser | Operating System | OPFS Support | Notes |
|---|---|---|---|
| Chrome | Windows, macOS, Linux, Android | ✅ Supported | Full support since version 86+. |
| Edge (Chromium-based) | Windows, macOS | ✅ Supported | Same as Chrome, fully supported. |
| Safari | macOS 12.2+, iOS 15.2+ | ✅ Supported | Full support starting macOS 12.2+ and iOS 15.2+. |
| Safari | macOS < 12.2, iOS < 15.2 | ❌ Not Supported | OPFS is not supported on older OS versions. |
| Safari (Private Browsing) | macOS & iOS | ⚠️ Not Available | OPFS is not available in Safari’s Private Browsing mode. |
| Firefox | Windows, macOS, Linux | ⚠️ Partial Support | Available in Firefox 111+, but support is still incomplete compared to Chromium browsers. |
| Internet Explorer | All OSes | ❌ Not Supported | Legacy browser; does not support modern APIs like OPFS. |
FileSystemSyncAccessHandle are only available in Web Workers.QuotaExceededError accordingly.<script src="https://cdn.jsdelivr.net/npm/opfs-js@1.0.0/opfs.js"></script>
or
<script src="https://unpkg.com/opfs-js@1.0.0/opfs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/opfs-js@1.0.0/opfs.min.js"></script>
or
<script src="https://unpkg.com/opfs-js@1.0.0/opfs.min.js"></script>
npm install opfs-js
import OPFS from 'opfs-js';
const OPFS = require('opfs.js');
<script type="module">
import OPFS from 'https://cdn.jsdelivr.net/npm/opfs-js/opfs.js/+esm';
</script>
const opfs = OPFS();
await opfs.writeFile('hello.txt', 'Hello World');
const fileData = await opfs.readFile('hello.txt');
console.log(await fileData.toText()); // "Hello World"
await opfs.appendFile('hello.txt', '\nMore');
await opfs.renameFile('hello.txt', 'greeting.txt');
await opfs.copyFile('greeting.txt', 'copy.txt');
const exists = await opfs.fileExists('copy.txt');
console.log(exists); // true
const files = await opfs.listFiles('.');
console.log(files); // ['greeting.txt', 'copy.txt']
| Method | Parameters | Returns | Example | Description |
|---|---|---|---|---|
writeFile | (path, content) | Promise<void> | await opfs.writeFile('a.txt', 'text') | Writes string or Blob to a file |
readFile | (path) | Promise<FileData> | let data = await opfs.readFile('a.txt') | Reads a file and returns FileData wrapper |
appendFile | (path, content) | Promise<void> | await opfs.appendFile('a.txt', 'text') | Appends content to a file |
deleteFile | (path) | Promise<void> | await opfs.deleteFile('a.txt') | Deletes a file |
renameFile | (oldPath, newPath) | Promise<void> | await opfs.renameFile('old.txt', 'new.txt') | Renames a file |
copyFile | (src, dest) | Promise<void> | await opfs.copyFile('a.txt', 'b.txt') | Copies a file |
fileExists | (path) | Promise<boolean> | await opfs.fileExists('a.txt') | Checks if a file exists |
readDir | (dirPath) | Promise<Array<FileMeta>> | await opfs.readDir('myDir') | Lists files with metadata |
listFiles | (dirPath) | Promise<Array<string>> | await opfs.listFiles('.') | Lists filenames only |
listDirectories | (dirPath) | Promise<Array<string>> | await opfs.listDirectories('.') | Lists subdirectory names |
readAllFiles | (dirPath) | Promise<Array<string>> | await opfs.readAllFiles('.') | Recursively lists all file paths |
readAllDirectories | (dirPath) | Promise<Array<string>> | await opfs.readAllDirectories('.') | Recursively lists all directories |
createDirectory | (path) | Promise<void> | await opfs.createDirectory('myDir') | Creates a new directory |
deleteDirectory | (path) | Promise<void> | await opfs.deleteDirectory('myDir') | Deletes a directory |
renameDirectory | (oldPath, newPath) | Promise<void> | await opfs.renameDirectory('old', 'new') | Renames a directory |
dirExists | (path) | Promise<boolean> | await opfs.dirExists('dir') | Checks if directory exists |
resolvePath | (path) | string | opfs.resolvePath('./a/../b') | Returns normalized path |
joinPath | (...paths) | string | opfs.joinPath('a', 'b') | Joins path parts |
splitPath | (path) | Array<string> | opfs.splitPath('a/b') | Splits path into parts |
getParentDirectory | (path) | string | opfs.getParentDirectory('a/b') | Returns parent path |
getFileHandle | (path) | Promise<FileSystemFileHandle> | await opfs.getFileHandle('file.txt') | Returns file handle |
getDirectoryHandle | (path) | Promise<FileSystemDirectoryHandle> | await opfs.getDirectoryHandle('dir') | Returns directory handle |
ensurePermission | (handle, mode) | Promise<boolean> | await opfs.ensurePermission(handle, 'readwrite') | Requests permission for handle |
getFileMeta | (path) | Promise<object> | await opfs.getFileMeta('a.txt') | Returns metadata info |
isReadable | (path) | Promise<boolean> | await opfs.isReadable('a.txt') | Checks readability |
isWritable | (path) | Promise<boolean> | await opfs.isWritable('a.txt') | Checks writability |
streamFile | (path) | Promise<ReadableStream> | await opfs.streamFile('file.txt') | Returns file read stream |
writeStream | (path) | Promise<WritableStreamDefaultWriter> | let writer = await opfs.writeStream('file.txt') | Returns writable stream |
readFileChunk | (path, start, end) | Promise<ArrayBuffer> | await opfs.readFileChunk('a.txt', 0, 5) | Reads part of file |
importFile | (File, destPath) | Promise<void> | await opfs.importFile(file, 'name.txt') | Imports a file object |
exportFile | (path) | Promise<Blob> | let blob = await opfs.exportFile('a.txt') | Exports file as Blob |
getQuota | () | Promise<{usage, quota}> | await opfs.getQuota() | Returns storage info |
clearOPFS | () | Promise<void> | await opfs.clearOPFS() | Clears OPFS files |
debugTree | (dirPath) | Promise<string> | await opfs.debugTree('.') | Visual directory tree |
.toText() | () | Promise<string> | await fileData.toText() | Reads content as text |
.toBlob() | () | Promise<Blob> | await fileData.toBlob() | Converts to Blob |
.toJSON() | () | Promise<object> | await fileData.toJSON() | Parses JSON content |
.toArrayBuffer() | () | Promise<ArrayBuffer> | await fileData.toArrayBuffer() | Converts to ArrayBuffer |
.toDataURL() | () | Promise<string> | await fileData.toDataURL() | Converts to base64 URL |
MIT
If you'd like, I can add a real README.md file for your project and update it automatically. Want me to do that?
FAQs
Simplified access to browser's Origin Private File System (OPFS) for persistent client-side file storage.
We found that opfs-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.