Persistent browser storage. Familiar file APIs.

Many files. Few handles.
Synchronous I/O.

A virtual filesystem for the Origin Private File System (OPFS). Use synchronous I/O inside a worker, and inspect your files through familiar paths.

Effect v4 adapter New

Built around your files

Your storage layer for

Give browser tools and apps familiar paths to files that persist across sessions.

See what you store

Find the file.
Read what it holds.

Browse the file behind a bug, inspect its contents, and edit it in place. Volume Explorer and the just-bash shell work directly with your OPFS VFS files.

Explore a real volume
An app-specific IndexedDB layoutWhat do these entries contain?
chunk:8f2a:0
ArrayBuffer(4096)
chunk:8f2a:1
ArrayBuffer(1024)
inode:8f2a
{ blocks: [0, 1], … }

DevTools shows the records. Making sense of the files may mean decoding the application's keys, chunks, and metadata.

Illustrative records. Filesystem layouts vary.
With OPFS VFS toolsA path to the file you need.
/workspace
├── documents/
│   └── notes.md
└── data/
    └── results.csv
Read it with just-bash
cat /workspace/documents/notes.md
Ideas for the next release.
Example paths and file contents.

IndexedDB can also power a filesystem and explorer. OPFS VFS brings the path API, explorer, previews, and just-bash integration together. Files live inside a browser-local volume, not in folders on your desktop.

Synchronous at the core

File I/O.
Without the
await.

After setup, reads and writes return directly inside a dedicated worker. No promise round trip for each file operation.

Useful for databases, WebAssembly runtimes, and workloads with many small operations. Your interface stays connected through the asynchronous worker client.

Compare real workloads
worker.tsTypeScript · Dedicated worker
import { OpfsVfs, OpenFlags } from '@opfs-vfs/opfs-vfs';

const fs = new OpfsVfs('project.bin');
await fs.ready;

const content: Uint8Array = new TextEncoder().encode('Hello');
const fd = fs.openSync('/notes.txt',
  OpenFlags.O_CREAT | OpenFlags.O_RDWR);
try {
  fs.writeSync(fd, content);
  fs.fsyncSync(fd);
} finally {
  fs.closeSync(fd);
}
await fs.closeVfs();

Await setup once. Read and write synchronously.
Synchronize important writes before closing the file.

IndexedDB uses asynchronous requests. Actual throughput depends on the workload, browser, buffering, and durability settings. Compare storage settings.

Persistence you control

Disk buffering and balanced durability are the defaults. Choose when to synchronize important writes, then reopen the same volume in your next session.

How saving works

TypeScript · React · Effect

One filesystem.
Use it your way.

Work with persistent browser files in TypeScript, build reactive interfaces with React, or compose storage into Effect workflows.

TypeScript

Core API

Read and write files by path.

Read and write files through the asynchronous worker client, or use synchronous I/O inside a worker.

@opfs-vfs/opfs-vfsGet started

Effect

Adapter · Effect v4

Use Effect's FileSystem service.

Read and write browser-local files with typed errors and scoped resources. Subscribe to file changes with streams.

@opfs-vfs/effectExplore the Effect adapter Requires stable Effect v4, starting at 4.0.0 and excluding v5 and prereleases.

Get started

The same file.
Your preferred API.

Read /note.txt from notes.bin with each API. These examples assume the file already exists in that volume.

Create your first browser volume →

Requires HTTPS or localhost and cross-origin isolation. Browser setup →

main.tsCore API
import { OpfsVfsWorker } from '@opfs-vfs/opfs-vfs/worker';

const fs = new OpfsVfsWorker('notes.bin');
try {
  await fs.ready;
  const bytes = await fs.readFileBuffer('/note.txt');
  console.log(new TextDecoder().decode(bytes));
} finally {
  await fs.closeVfs();
}
Read the getting started guide →
App.tsxSDK · Preview
import { VolumeProvider, useFileContent } from '@opfs-vfs/react';

function Note() {
  const note = useFileContent('/note.txt', { format: 'text' });
  if (note.status === 'pending') return <p>Loading…</p>;
  if (note.status === 'error') return <p role="alert">{note.error.message}</p>;
  return <pre>{note.data}</pre>;
}

export function App() {
  return <VolumeProvider fileName="notes.bin"><Note /></VolumeProvider>;
}
Read the React guide →
filesystem.tsAdapter · Effect v4
import { Effect, FileSystem, Layer } from 'effect';
import { OpfsFileSystem, Volume } from '@opfs-vfs/effect';

const live = Layer.provide(
  OpfsFileSystem.layer,
  Volume.layer({ fileName: 'notes.bin' }),
);

const readNote = Effect.gen(function* () {
  const fs = yield* FileSystem.FileSystem;
  return yield* fs.readFileString('/note.txt');
}).pipe(Effect.provide(live));

console.log(await Effect.runPromise(readNote));
Read the Effect guide →

Adapters & tools

Shells. Databases.
File tools.

Start with ready-to-use adapters for databases and shell workflows, plus a Volume Explorer to inspect your application's files. Reuse the storage integration and developer tools across different applications.

Available

Ready to use, with demos and integration guides.

just-bash

Bash shell

Use familiar shell commands, pipes, and scripts through a POSIX-style filesystem interface. Build document workspaces and AI tools around persistent files.

Experimental

Adapters in development.

Planned

On the roadmap. Not available yet.

SurrealDB

Database

A planned adapter to connect SurrealDB to persistent storage through OPFS VFS.

Deferred pending changes across upstream projects

Browser model skill

AI tools

A reusable filesystem skill for models running in the browser, with tools to find, read, and write workspace files.

Volume export & import

Take your files
with you.

Export your workspace files and folders as a ZIP, then import them into a new volume. Keep a backup, share a project, or move your workspace to another browser.

Try export & import
Files and folders exported from one browser workspace as a ZIP archive, then restored in another.
WorkspaceZIP archiveNew volume

Working with PGlite? Export and import its native database archives

Why OPFS VFS

Thousands of paths.
A bounded set of handles.

Store many files without opening a native handle for each one. OPFS VFS manages the volume layout and gives your application synchronous file access inside a worker.

Why we built OPFS VFS →
Many file and folder paths converge through a few connections into one storage volume.

Privacy-sensitive applications

Keep sensitive files on the device.

Build document tools, local databases, and on-device AI workflows that process files in the browser. OPFS VFS stores those files locally, so your app can work with them without uploading their contents to a server.

Documents, folders, and a database connected within a laptop's browser workspace.

Files as app state

You might not need a local database.

If your app works with documents, keep files as its source of truth. Subscribe to changes, reread affected paths, and update the UI. You may not need a separate local database or global state store.

Explore file subscriptions →
  1. 01Write a file/workspace/notes.md
  2. 02Get a change eventThe subscription reports the path.
  3. 03Reread and renderThe UI shows the current file.

Plugins

Add capabilities with plugins.

Use file subscriptions to refresh your UI when files change. Add encrypted local storage when files need protection. Build a custom plugin for different storage or change behavior.

File changes notify subscribed components across tabs.Two tabs on the same origin subscribe to the same volume. Creating, editing, or deleting task.txt notifies both tabs. Each application rereads the file and updates its todo component.Same origin · same volumetask.txtBuy milkBuy oat milkTab 1Todo componentsubscribedBuy milkBuy oat milkTab 2Todo componentsubscribedBuy milkBuy oat milkOPFS VFSShared volume/todosCreate file → Notify both tabsUpdate file → Notify both tabsDelete file → Notify both tabsOne volume → Change events across tabs

Available Community

File subscriptions plugin

Receive file change events across tabs using the same volume and origin. Reread affected paths to refresh your UI.

Use subscriptions
Passkey authentication protects an encrypted local volume.

Available Premium

Encryption plugin

Protect files stored on the device with encrypted volumes and passkey-based access. Available under separate premium terms.

About encryption

Browser support

Built for today's browsers.

OPFS VFS uses the origin-private file system and synchronous file access in a dedicated worker. These browsers provide the required APIs from the versions shown.

BrowserMinimum API version
Chrome108+Desktop · Android 109+
Edge108+Desktop
Firefox111+Desktop & Android
Safari16.4+macOS, iOS & iPadOS

Version numbers reflect browser API availability, not a test guarantee for every release. Use HTTPS or localhost; the worker client also needs cross-origin isolation. Browser setup →

Benchmarks

Compare storage performance.

Compare OPFS VFS with PGlite's OPFS AHP, IndexedDB, and memory-only backends. See the measured results, settings, and raw samples, or run the workloads on your device.

A storage volume, folders, a database, and a memory module shown side by side.Benchmark overview →

Start a conversation

Building something that needs a place for its files?

Tell us about it. We’d love to hear what you’re making with OPFS VFS.