Filesystems
PGlite has a virtual file system layer that allows it to run in environments that don't traditionally have filesystem access.
PGlite VFSs are under active development, and we plan to extend the range of options in future, as well as make it easy for users to create their own filesystems.
We would recommend using the IndexedDB VFS in the browser at the current time as the OPFS VFS is not supported by Safari.
In-memory FS
The in-memory FS is the default when starting PGlite, and it is available on all platforms. All files are kept in memory and there is no persistance, other than calling pg.dumpDataDir()
and then using the loadDataDir
option at start.
To use the in-memory FS you can use one of these methods:
- Don't provide a
dataDir
optiontsconst pg = new PGlite()
- Set the
dataDir
tomemory://
tsconst pg = new PGlite('memory://')
- Import and pass the FS explicitlyts
import { MemoryFS } from '@electric-sql/pglite' const pg = new PGlite({ fs: new MemoryFS(), })
Platform Support
Node | Bun | Chrome | Safari | Firefox |
---|---|---|---|---|
✓ | ✓ | ✓ | ✓ | ✓ |
Node FS
The Node FS uses the Node.js file system API to implement a VFS for PGLite. It is available in both Node and Bun.
To use the Node FS you can use one of these methods:
- Set the
dataDir
to a directory on your filesystemtsconst pg = new PGlite('./path/to/datadir/')
- Import and pass the FS explicitlyts
import { NodeFS } from '@electric-sql/pglite' const pg = new PGlite({ fs: new NodeFS('./path/to/datadir/'), })
Platform Support
Node | Bun | Chrome | Safari | Firefox |
---|---|---|---|---|
✓ | ✓ |
IndexedDB FS
The IndexedDB FS persists the database to IndexedDB in the browser. It's a layer over the in-memory filesystem, loading all files for the database into memory on start, and flushing them to IndexedDB after each query if they have changed.
To use the IndexedDB FS you can use one of these methods:
- Set the
dataDir
with aidb://
prefix, the database will be stored in an IndexedDB named with the path providedtsconst pg = new PGlite('idb://my-database')
- Import and pass the FS explicitlyts
import { IdbFs } from '@electric-sql/pglite' const pg = new PGlite({ fs: new IdbFs('my-database'), })
The IndexedDB filesystem works at the file level, storing whole files (Postgres has a single file per table or index) as blobs in IndexedDB. Flushing whole files can take a few milliseconds after each query. To aid in building responsive apps we provide a relaxedDurability
mode that can be configured when starting PGlite. Under this mode, the results of a query are returned immediately, and the flush to IndexedDB is scheduled to occur asynchronously afterwards. Typically, this is immediately after the query returns with no delay.
Platform Support
Node | Bun | Chrome | Safari | Firefox |
---|---|---|---|---|
✓ | ✓ | ✓ |
OPFS AHP FS
The OPFS AHP filesystem is built on top of the Origin Private Filesystem in the browser and uses an "access handle pool". It is only available when PGlite is run in a Web Worker, this could be any worker you configure. We provide a Multi Tab Worker to aid in using PGlite from multiple tabs in the browser.
To use the OPFS AHP FS you can use one of these methods:
- Set the
dataDir
to a directory within the origins OPFStsconst pg = new PGlite('opfs-ahp://path/to/datadir/')
- Import and pass the FS explicitlyts
import { OpfsAhpFS } from '@electric-sql/pglite/opfs-ahp' const pg = new PGlite({ fs: new OpfsAhpFS('./path/to/datadir/'), })
Platform Support
Node | Bun | Chrome | Safari | Firefox |
---|---|---|---|---|
✓ | ✓ |
Unfortunately, Safari appears to have a limit of 252 open sync access handles, this prevents this VFS from working due to a standard Postgres install consisting of over 300 files.
What is an "access handle pool"?
The Origin Private Filesystem API provides both asynchronous and synchronous methods, but the synchronous methods are limited to read, write and flush. You are unable to traverse the filesystem or open files synchronously. PGlite is a fully synchronous WASM build of Postgres and unable to call async APIs while handling a query. While it is possible to build an async WASM Postgres using Asyncify, it adds significant overhead in both file size and performance.
To overcome these limitations, and to provide a fully synchronous file system to PGlite on top of OPFS, we use something called an "access handle pool". When you first start PGlite we open a pool of OPFS access handles with randomised file names; these are then allocated to files as needed. After each query, a pool maintenance job is scheduled that maintains its size. When you inspect the OPFS directory where the database is stored, you will not see the normal Postgres directory layout, but rather a pool of files and a state file containing the directory tree mapping along with file metadata.
The PGlite OPFS AHP FS is inspired by the wa-sqlite access handle pool file system by Roy Hashimoto.