PGlite
Embedded PostgreSQL using WebAssembly
Installation
pnpm add @electric-sql/pglite
Configuration
import { createClient } from "viborm/pglite";
const client = createClient({
schema,
});
Options
| Option | Type | Description |
|---|---|---|
client |
PGlite |
Existing PGlite instance |
dataDir |
string |
Data directory for persistence |
options |
PGliteOptions |
PGlite configuration |
pgvector |
boolean |
Enable pgvector support |
postgis |
boolean |
Enable PostGIS support |
In-Memory Database
import { createClient } from "viborm/pglite";
// Default is in-memory
const client = createClient({
schema,
});
Persistent Database
import { createClient } from "viborm/pglite";
const client = createClient({
dataDir: "./pglite-data",
schema,
});
Using Existing Instance
import { PGlite } from "@electric-sql/pglite";
import { createClient } from "viborm/pglite";
const pg = new PGlite();
const client = createClient({
client: pg,
schema,
});
Use Cases
- Local development: Full PostgreSQL without Docker
- Testing: Fast, isolated database per test
- Browser: PostgreSQL in the browser via WASM
- Edge: Serverless functions with embedded database
Transactions
PGlite supports full transactions with savepoints for nested transactions — see Transactions.
Do not benchmark query plans on PGlite
PGlite starts with enable_seqscan = off. It is set on the server’s command
line, not by viborm, and it is not the default a real PostgreSQL server runs
with:
await client.$queryRawUnsafe(
"SELECT setting, source FROM pg_settings WHERE name = 'enable_seqscan'"
);
// [{ setting: "off", source: "command line" }] ← PGlite 17.4 (WASM), as shipped
With it off the planner charges a sequential scan an enormous cost, so it takes an index whenever one can answer the query — whether or not the index is the cheaper plan. That makes PGlite the wrong place to ask “does my index get used”, because the answer is almost always yes.
If you are measuring a plan rather than a result, either turn it back on for the session and check that the setting took:
await client.$executeRawUnsafe("SET enable_seqscan = on");
const [{ enable_seqscan }] = await client.$queryRawUnsafe("SHOW enable_seqscan");
// assert it is "on" before trusting the EXPLAIN below
or run the measurement against a real PostgreSQL server. Correctness results are unaffected — a plan choice changes the cost, never the rows.
Limitations
- WASM-based: may have performance overhead for heavy workloads
- Some PostgreSQL extensions not available
enable_seqscanisoffat startup — see the section above before reading anyEXPLAINtaken here as a statement about production