Skip to main content
Zero Cache is the core server component that manages real-time synchronization between PostgreSQL and clients. It maintains a local SQLite replica of your upstream PostgreSQL database and handles incremental view maintenance for connected clients.

Architecture

Zero Cache follows a sync-first architecture:
PostgreSQL (upstream) → Zero Cache (SQLite replica) → Clients (IndexedDB)

Components

  • Replication Manager: Streams changes from PostgreSQL using logical replication
  • View Syncers: Process client queries and maintain incremental views
  • Change Streamer: Distributes database changes to view syncers
  • SQLite Replica: Local copy of upstream data for fast query execution

Installation

Zero Cache is included in the @rocicorp/zero package:
npm install @rocicorp/zero

Running Zero Cache

Development Mode

Use zero-cache-dev for local development with schema hot-reloading:
npm run zero-cache-dev
This command:
  • Starts Zero Cache on port 4848 (default)
  • Watches for schema changes and auto-restarts
  • Uses lower resource limits suitable for development
  • Defaults to NODE_ENV=development

Production Mode

Run the cache server directly:
zero-cache

Configuration

Configure Zero Cache using environment variables with the ZERO_ prefix or CLI flags.

Required Configuration

# PostgreSQL connection string
ZERO_UPSTREAM_DB=postgresql://user:password@localhost:5432/mydb

# API endpoints for mutations and queries
ZERO_MUTATE_URL=https://api.example.com/mutate
ZERO_QUERY_URL=https://api.example.com/query

Common Options

Environment VariableCLI FlagDefaultDescription
ZERO_PORT--port4848Port for sync connections
ZERO_APP_ID--app-idzeroUnique app identifier
ZERO_REPLICA_FILE--replica-filezero.dbPath to SQLite replica
ZERO_UPSTREAM_MAX_CONNS--upstream-max-conns20Max connections to PostgreSQL
ZERO_CVR_MAX_CONNS--cvr-max-conns30Max CVR database connections
ZERO_NUM_SYNC_WORKERS--num-sync-workersautoNumber of sync worker processes
ZERO_ADMIN_PASSWORD--admin-password-Password for admin endpoints

Database Configuration

# Optional: Separate CVR database
ZERO_CVR_DB=postgresql://user:password@localhost:5432/cvr_db

# Optional: Separate change log database
ZERO_CHANGE_DB=postgresql://user:password@localhost:5432/change_db

# Publications to replicate (defaults to all tables in public schema)
ZERO_APP_PUBLICATIONS=my_publication

Performance Tuning

# Query optimization
ZERO_ENABLE_QUERY_PLANNER=true
ZERO_YIELD_THRESHOLD_MS=10

# CVR garbage collection
ZERO_CVR_GARBAGE_COLLECTION_INACTIVITY_THRESHOLD_HOURS=48
ZERO_CVR_GARBAGE_COLLECTION_INITIAL_BATCH_SIZE=25

# Replica vacuuming (optional)
ZERO_REPLICA_VACUUM_INTERVAL_HOURS=168  # Once per week

WebSocket Configuration

# Enable compression (disabled by default)
ZERO_WEBSOCKET_COMPRESSION=true

# Max message size (default 10MB)
ZERO_WEBSOCKET_MAX_PAYLOAD_BYTES=10485760

Multi-Node Deployment

For production, deploy with a replication manager and multiple view syncers:

Replication Manager

Runs the PostgreSQL replication stream and change streamer:
# Set sync workers to 0 for replication manager only
ZERO_NUM_SYNC_WORKERS=0
ZERO_LITESTREAM_BACKUP_URL=s3://my-bucket/backup

View Syncers

Connect to the replication manager:
# Point to replication manager
ZERO_CHANGE_STREAMER_URI=http://replication-manager:4849

# Or use discovery mode
ZERO_CHANGE_STREAMER_MODE=discover

Litestream Integration

Zero Cache supports Litestream for SQLite replica backup and restore:
# S3 backup location
ZERO_LITESTREAM_BACKUP_URL=s3://my-bucket/replica-backup

# Backup intervals
ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_MINUTES=15
ZERO_LITESTREAM_SNAPSHOT_BACKUP_INTERVAL_HOURS=12

# Checkpoint settings
ZERO_LITESTREAM_CHECKPOINT_THRESHOLD_MB=40

App Isolation

Multiple Zero apps can share a PostgreSQL instance using the ZERO_APP_ID:
ZERO_APP_ID=production_app
Each app gets isolated schemas:
  • {app-id} - App metadata
  • {app-id}_0 - Shard 0 metadata (client/mutation IDs)
  • {app-id}_0/cvr - Client view records
  • {app-id}_0/cdc - Change data capture

Initial Sync

On first startup, Zero Cache performs an initial sync from PostgreSQL:
# Parallelism for table copy
ZERO_INITIAL_SYNC_TABLE_COPY_WORKERS=5
Initial sync progress is logged. The replica file can be safely deleted to trigger a re-sync.

Monitoring

Health Check Endpoint

curl http://localhost:4848/keepalive

Stats Endpoint

Requires admin password:
curl -u admin:$ZERO_ADMIN_PASSWORD http://localhost:4848/statz

OpenTelemetry

Zero Cache exports traces and metrics:
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel-collector:4318
OTEL_EXPORTER_OTLP_HEADERS="x-api-key=..."

Rate Limiting

Limit mutations per user:
# Max 100 mutations per user per minute
ZERO_PER_USER_MUTATION_LIMIT_MAX=100
ZERO_PER_USER_MUTATION_LIMIT_WINDOW_MS=60000

Development Tools

Schema Hot Reload

zero-cache-dev watches your schema file and auto-restarts:
zero-cache-dev --schema-path ./shared/schema.ts

Debug Mode

Run with Node debugger:
npm run zero-brk  # Starts with --inspect-brk

Query Debugging

# Transform ZQL to SQL
transform-query

# Run a query against the replica
run-query

Error Handling

Auto Reset

Automatically reset replica on schema changes:
ZERO_AUTO_RESET=true  # Default
When disabled, schema changes halt replication with an error.

Lazy Startup

Delay connection until first client request:
ZERO_LAZY_STARTUP=true
Useful for preview environments to avoid idle PostgreSQL connections.

Security

Admin Password

Required in production:
ZERO_ADMIN_PASSWORD=secure_random_password
In development mode (NODE_ENV=development), admin endpoints work without a password. Forward authentication cookies to mutation/query handlers:
ZERO_MUTATE_FORWARD_COOKIES=true
ZERO_QUERY_FORWARD_COOKIES=true

Custom Headers

Allow specific client headers:
ZERO_MUTATE_ALLOWED_CLIENT_HEADERS=x-request-id,x-correlation-id
ZERO_QUERY_ALLOWED_CLIENT_HEADERS=x-request-id

Telemetry

Anonymous usage telemetry is enabled by default:
# Opt out
ZERO_ENABLE_TELEMETRY=false

# Or set
DO_NOT_TRACK=1

Troubleshooting

Port Already in Use

lsof -i :4848 | grep LISTEN
kill <PID>

Connection Pool Exhaustion

Increase connection limits:
ZERO_UPSTREAM_MAX_CONNS=40
ZERO_CVR_MAX_CONNS=60
Ensure limits allow at least one connection per sync worker.

Out of Memory

Reduce sync workers or back pressure limit:
ZERO_NUM_SYNC_WORKERS=2
ZERO_CHANGE_STREAMER_BACK_PRESSURE_LIMIT_HEAP_PROPORTION=0.03

Slow Initial Sync

Increase table copy workers:
ZERO_INITIAL_SYNC_TABLE_COPY_WORKERS=10
Note: Bottlenecks may be disk I/O, upstream CPU, or network bandwidth.

Next Steps

Build docs developers (and LLMs) love