description: How SurfSense uses Rocicorp Zero for instant real-time data synchronization
---
# Real-Time Sync with Zero
SurfSense uses [Rocicorp Zero](https://zero.rocicorp.dev/) for real-time data synchronization. Zero continuously replicates data from PostgreSQL to a local cache on each client, enabling instant UI updates for notifications, documents, connectors, chat messages, and comments.
## How It Works
Zero runs a **zero-cache** server that sits between PostgreSQL and the browser:
1. **zero-cache** replicates data from PostgreSQL into a local SQLite replica using logical replication
2. The browser connects to zero-cache via WebSocket and syncs relevant data locally
3. When data changes in PostgreSQL (e.g., a new notification), zero-cache pushes the update to all connected clients instantly
4. Queries run against local data first for instant results, then update when server data arrives
## Architecture
| Component | Role |
|-----------|------|
| **PostgreSQL** | Source of truth (with `wal_level=logical`) |
If running the frontend outside Docker (e.g., `pnpm dev`), you need:
1. A running zero-cache instance pointing at your PostgreSQL database
2. `NEXT_PUBLIC_ZERO_CACHE_URL` set in your `.env` file (default: `http://localhost:4848`)
### Custom Domain / Reverse Proxy
When deploying behind a reverse proxy, set `NEXT_PUBLIC_ZERO_CACHE_URL` to your public zero-cache URL (e.g., `https://zero.yourdomain.com`). The zero-cache service must be accessible via WebSocket from the browser.
zero-cache connects to PostgreSQL using logical replication. The database must meet these requirements:
1. **`wal_level = logical`** — already configured in the bundled `postgresql.conf`
2. **The database user must have `REPLICATION` privilege** — required for creating logical replication slots
In the default Docker setup, the `surfsense` user is a PostgreSQL superuser and has all required privileges automatically.
**For managed databases** (RDS, Supabase, Cloud SQL, etc.) where the app user may not be a superuser, you need to grant replication privileges:
```sql
ALTER USER surfsense WITH REPLICATION;
GRANT CREATE ON DATABASE surfsense TO surfsense;
```
The `REPLICATION` privilege allows zero-cache to create a logical replication slot for streaming changes. The `CREATE` privilege allows zero-cache to create internal schemas (`zero`, `zero_0`) for its metadata.
- **"Insufficient upstream connections" error**: zero-cache defaults `ZERO_NUM_SYNC_WORKERS` to the number of CPU cores, which can exceed connection pool limits on high-core machines. Lower `ZERO_NUM_SYNC_WORKERS` or raise `ZERO_UPSTREAM_MAX_CONNS` / `ZERO_CVR_MAX_CONNS` in your `.env`.
- **Frontend not syncing**: Open DevTools → Console and check for WebSocket connection errors. Verify `NEXT_PUBLIC_ZERO_CACHE_URL` matches the running zero-cache address.
- **Stale data after restart**: zero-cache rebuilds its SQLite replica from PostgreSQL on startup. This may take a moment for large databases.
## Learn More
- [Rocicorp Zero Documentation](https://zero.rocicorp.dev/docs)