Add to Existing Project
Zero integrates effortlessly into JavaScript or TypeScript projects, whether you're using React, Vue, Svelte, Solid, or vanilla JavaScript.
Prerequisites
- A PostgreSQL database with Write-Ahead Logging (WAL) enabled. See Connecting to Postgres for setup instructions.
Installation
Install the Zero package:
npm install @rocicorp/zero
Note: If you're using pnpm or bun, additional steps are required to install native binaries. Refer to Not using npm? for details.
Environment Variables
Configure Zero by creating a .env
file in your project root:
ZERO_UPSTREAM_DB="postgresql://user:password@127.0.0.1/postgres"
ZERO_REPLICA_FILE="/tmp/sync-replica.db"
Replace the placeholders with your database connection details. For more options, see configuration options.
Starting the Server
Start the Zero server using the CLI:
npx zero-cache
The server runs on port 4848 by default. To verify, open http://localhost:4848
in your browser. If everything is configured correctly, you'll see "OK".
Defining Your Schema
Define your data model schema as described in the Zero schema documentation.
Example:
// schema.ts
import {createSchema, table, string} from '@rocicorp/zero';
const message = table('message')
.columns({
id: string(),
body: string(),
})
.primaryKey('id');
export const schema = createSchema({
tables: [message],
});
export type Schema = typeof schema;
If you're using Prisma or Drizzle, you can convert their schemas to Zero schemas using tools listed in the community section.
Permissions
Update schema.ts
to include permissions for your tables. For example, to allow
all users to read and write to the message
table, add the following:
// schema.ts
import {ANYONE_CAN_DO_ANYTHING, definePermissions} from '@rocicorp/zero';
export const permissions = definePermissions<unknown, Schema>(schema, () => ({
message: ANYONE_CAN_DO_ANYTHING,
}));
For more details, see permissions.
Creating a Zero Instance
To create a Zero client instance:
import {Zero} from '@rocicorp/zero';
const z = new Zero({
userID: 'anon',
server: 'http://localhost:4848',
schema,
});
In production, avoid hardcoding the server URL. Use environment variables like
import.meta.env.VITE_PUBLIC_SERVER
or process.env.NEXT_PUBLIC_SERVER
.
Reading Data
To read data, use the materialize
method on a Query
from the Zero
instance. This creates a materialized view that listens for real-time updates to
the data:
const view = z.query.message.materialize();
view.addListener(data => console.log('Data updated:', data));
When the view is no longer needed, ensure you clean up by destroying it:
view.destroy();
For more details, see Reading Data with ZQL.
React
React developers can use the useZero
hook for seamless integration. See
Integrations React for more details.
SolidJS
For SolidJS, use the createZero
function instead of new Zero
.
Refer to Integrations SolidJS for additional information.
Other Frameworks
For other frameworks, see the UI frameworks documentation.
Writing Data
Zero supports both simple and advanced data mutations. For basic use cases, use the CRUD mutator:
z.mutate.message.insert({id: nanoid(), body: 'Hello World!'});
For more complex scenarios, such as custom business logic, use custom mutators to define tailored mutation behavior.
Server-Side Rendering (SSR)
Zero does not currently support SSR. Use client-only patterns to prevent SSR execution:
Next.js
Add the use client
directive.
SolidStart
Wrap components that use Zero with the
clientOnly
higher-order component.
The standard clientOnly
pattern uses dynamic imports, but note that this
approach (similar to React's lazy
)
works with any function returning a Promise<{default: () => JSX.Element}>
. If
code splitting is unnecessary, you can skip the dynamic import.
TanStack Start
Use React's lazy
for dynamic
imports.
Deployment
Ensure all .env
variables are set in the production environment. For Zero
cache deployment, see Deployment. For frontend deployment, consult
your framework's documentation.