Benchmarks / storage guide
Storage modes and durability
Choose where files live, how the VFS uses memory, and when it synchronizes changes. These are separate settings, and each affects how you should compare the benchmark results.
For the story behind the filesystem, read why we built OPFS VFS.
Where does the data live?
All four SQL backends run the same PGlite database engine. What changes is the way it stores database files.
| Backend | How it stores files | After the session |
|---|---|---|
| PGlite memory | Temporary working memory, or RAM. | Gone unless you explicitly export and later restore it. |
| PGlite IndexedDB | Loads files into RAM and saves changed files into the browser's IndexedDB database. | Saved data can be reopened locally. |
| PGlite OPFS AHP | A pool of open file handles connects database files to OPFS storage. | Saved data can be reopened locally. |
| OPFS VFS | Maps many logical files into an OPFS volume, using a bounded set of handles. | Saved data can be reopened locally. |
OPFS is the browser's private filesystem for a website. AHP means access handle pool. Those handles let a worker read and write files. PGlite's IndexedDB backend saves whole changed files; it still keeps a working copy in RAM. See PGlite's filesystem guide for backend requirements.
OPFS VFS and access handle pools
Both OPFS VFS and PGlite OPFS AHP provide synchronous filesystem operations inside a worker. An ordinary OPFS VFS volume opens six backing-file handles, independent of the number of virtual files. PGlite AHP keeps handles for database files and a spare pool. The VFS layout reduces handle consumption as the virtual file count grows.
A WebKit change in August 2025 raised the NetworkProcess and GPUProcess file-descriptor limit toward 2,560, subject to system limits. This is a process-wide resource limit, not a guarantee of 2,560 OPFS handles per application or a fixed 1,000-file ceiling. A growing handle pool can still exhaust the available descriptors; the usable count depends on the browser build and other resource use.
AHP completed the published iPhone 17 Pro SQL runs in Safari 26.6.1. A separate user-reported Mac Safari attempt stalled with UnknownError: Invalid platform file handle. The cause and the device's handle limit were not measured. The Mac collection omitted AHP in Safari by protocol; those entries are not measured failures.
Browser support and performance depend on the environment and workload. AHP had the lower iPhone SQL-suite median, while disk-buffered OPFS VFS had the lower iPhone transaction median and lower medians in the Mac Chrome and Firefox comparisons. Neither result establishes a universal speed or durability advantage.
Memory and disk buffering
The VFS buffer setting applies only to OPFS VFS. Both choices use OPFS and can retain files across sessions.
Memory buffer
Keeps file contents in RAM for access. Writes also go into an OPFS recovery log, and synchronization copies changed data into the volume. RAM use grows with the files.
Disk buffer
Reads and writes the volume's data blocks directly. It avoids keeping a full extra copy of file contents in the VFS, though metadata and the database engine still use RAM.
VFS memory buffering is different from PGlite memory-only storage. Changing the buffer does not turn persistence off. Both the benchmark and the VFS library default to disk buffering. Memory buffering remains an explicit option.
When does a change reach disk?
A write can finish before every change has been flushed to disk. A flush asks the browser to persist pending changes. Local durability controls when OPFS VFS requests that work.
Relaxed
Defers flushes to an explicit synchronization request or an orderly close. This can reduce waiting, but unsynchronized work is more exposed to interruption.
Balanced
Groups changes and schedules synchronization about 150 milliseconds after the first change. A busy or suspended worker can delay it, so this is not a guaranteed limit on lost work.
Strict
With memory buffering, flushes appended file-data and namespace recovery-log records immediately. In the current implementation, strict does not add a flush to every disk-buffered write. Explicit synchronization still matters.
Both the benchmark and the library default to balanced. Relaxed remains available when an application manages synchronization explicitly. These settings describe flush policy, not an absolute guarantee against every kind of crash. See the persistence API guide and browser flush documentation.
PGlite has a separate durability setting
The benchmark's PGlite durability option controls whether database work waits for filesystem synchronization. It applies to all four SQL backends. The VFS settings above apply only to OPFS VFS.
With default PGlite durability, a query can trigger a VFS synchronization even if the VFS local mode is relaxed. Relaxed PGlite durability avoids waiting on that path; the VFS balanced timer or strict memory-log flushes still apply.
See the adapter guide and PGlite API reference for configuration.
Where to start
For an app that saves user work, start with Persistent storage only enabled. The benchmark's disk buffer, balanced local durability, and default PGlite durability give you a consistent starting point.
Try memory buffering when your files fit comfortably in RAM. Add PGlite memory-only to see the speed of temporary storage. Keep the settings beside the results when comparing runs.
The benchmark checks a clean close and reopen, then deletes its temporary databases. It does not simulate a crash. The full 16-case SQL suite drops its tables; the quick workloads check retained rows. Read the methodology for the exact checks.
Local storage is not a backup
IndexedDB and OPFS belong to a site's browser storage. Quotas vary, writes can fail when space runs out, and clearing site data removes saved files. Best-effort storage may also be evicted under storage pressure.
A granted browser persistent-storage request helps protect against automatic eviction. It does not prevent a user from deleting data, and it does not copy files to another device. This browser permission is separate from the benchmark's persistence toggle. See MDN's storage limits guide.
Applications should synchronize at meaningful save points, handle storage errors, and offer an export or backup for work users cannot afford to lose.