zero-pglite
v0.0.1
Published
PGlite-powered zero-sync development backend. No Docker required.
Maintainers
Readme
zerolite
Drop-in replacement for the Docker-based development backend that Rocicorp's Zero requires. Instead of running PostgreSQL, zero-cache, and MinIO in Docker containers, zerolite bundles everything into a single process using PGlite (PostgreSQL compiled to WASM).
The goal is simple: bun install && bun dev with zero system dependencies.
How it works
zerolite starts four things in one process:
- A PGlite instance (full PostgreSQL 16 running in-process via WASM)
- A TCP proxy that speaks the PostgreSQL wire protocol, including logical replication
- A zero-cache child process that connects to the proxy thinking it's a real Postgres server
- A minimal S3-compatible HTTP server for file uploads
The trick is in the TCP proxy. zero-cache needs logical replication to stay in sync with the upstream database. PGlite doesn't support logical replication natively, so zerolite fakes it. Every mutation is captured by triggers into a changes table, then encoded into the pgoutput binary protocol and streamed to zero-cache through the replication connection. zero-cache can't tell the difference.
The proxy also handles multi-database routing. zero-cache expects three separate databases (upstream, CVR, change), but PGlite is a single database. zerolite maps database names to schemas, so zero_cvr becomes the zero_cvr schema and zero_cdb becomes zero_cdb.
Install
npm install zeroliteor with bun:
bun add zeroliteYou also need @rocicorp/zero installed in your project for the zero-cache binary.
Usage
import { startZeroLite } from 'zerolite'
const { config, stop } = await startZeroLite({
pgPort: 6434,
zeroPort: 5849,
s3Port: 10201,
migrationsDir: 'src/database/migrations',
seedFile: 'src/database/seed.sql',
})
// your app connects to zero-cache at localhost:5849
// database is at postgresql://user:password@localhost:6434/postgres
// when done
await stop()All options are optional and have sensible defaults. See src/config.ts for the full list.
What gets faked
The proxy intercepts several things to convince zero-cache it's talking to a real PostgreSQL server with logical replication enabled:
IDENTIFY_SYSTEMreturns a fake system ID and timelineCREATE_REPLICATION_SLOTpersists slot info in a local table and returns a valid LSNSTART_REPLICATIONenters streaming mode, encoding changes as pgoutput binary messagescurrent_setting('wal_level')always returnslogicalpg_replication_slotsqueries are redirected to a local tracking tableSET TRANSACTION SNAPSHOTis silently accepted (PGlite doesn't support imported snapshots)ALTER ROLE ... REPLICATIONreturns successREAD ONLYis stripped from transaction starts to avoid PGlite serialization issues
The pgoutput encoder produces spec-compliant binary messages: Begin, Relation, Insert, Update, Delete, Commit, and Keepalive. All column values are encoded as text (typeOid 25), which zero-cache handles fine since it re-maps types downstream anyway.
Tests
78 tests across 5 test files covering the full stack from binary encoding to TCP-level integration:
bun testThe test suite includes a zero-cache compatibility layer that decodes pgoutput messages into the same typed format that zero-cache's PgoutputParser produces, validating end-to-end compatibility.
Limitations
This is a development tool. It is not suitable for production use.
- PGlite runs single-threaded. All queries are serialized through a mutex. This is fine for development but would be a bottleneck under real load.
- Column types are all encoded as text in the replication stream. Zero-cache handles this, but other pgoutput consumers might not.
- Triggers add overhead to every write. Again, fine for development.
- PGlite stores data on the local filesystem. No replication, no backups, no high availability.
- The S3 server is just a filesystem wrapper. No multipart uploads, no ACLs, no versioning.
Project structure
src/
index.ts main entry, orchestrates startup
config.ts configuration with defaults
pg-proxy.ts tcp proxy with query rewriting
pglite-manager.ts pglite instance and migration runner
s3-local.ts minimal s3 http server
replication/
handler.ts replication protocol state machine
pgoutput-encoder.ts binary pgoutput message encoder
change-tracker.ts trigger installation and change readerLicense
MIT
