Gerson

Gerson

Passionate developer specializing in web development, cloud architecture, and system design.

TypeScriptReactNext.jsPythonFastAPISQLNode.jsAWS

Zero 1.0: Local-First Sync That Works With Any Backend

Rocicorp's Zero hit 1.0 in 2026 — a general-purpose sync engine that makes reads instant and local while keeping any backend as the source of truth. Here is how it works and where it fits.

Gersonhttps://zero.rocicorp.dev/
A data pipeline visualization with flowing packets

Most web apps spend enormous effort re-implementing the same thing badly: keep a copy of some server data on the client, show it instantly, refetch it, reconcile it, and paper over the loading states in between. Local-first sync engines exist to make that a solved problem instead of a per-app project. In 2026 the category grew up — ElectricSQL, PowerSync, InstantDB, and others all matured — and Rocicorp shipped Zero 1.0, the first stable release of its general-purpose web sync engine after roughly two years and fifty-plus preview releases.

The pitch that sets Zero apart: it works with any backend. It does not require you to hand it your Postgres database the way some engines do — your server stays the source of truth, and Zero syncs a queried subset of it to the client.

The model: queries, not tables

The idea that makes Zero click is that you sync queries, not your whole database. You write a query with ZQL (Zero's query language), and Zero keeps exactly the rows that query needs synced to the client, backed by a local store and a server-side cache. Reads run against the local copy, so they are synchronous and instant — no spinner, no isLoading. Writes are applied optimistically on the client and sent to your server, which remains authoritative.

schema.ts + a synced query

import { useQuery } from "@rocicorp/zero/react";

// a component reads directly from the local, synced store
function Inbox({ userId }: { userId: string }) {
  // this query is what gets synced — not the whole table
  const [threads] = useQuery(
    z.query.thread
      .where("participantId", userId)
      .where("archived", false)
      .orderBy("lastMessageAt", "desc")
      .limit(50),
  );

  // threads is available synchronously; no loading state to manage
  return threads.map((t) => <ThreadRow key={t.id} thread={t} />);
}

Because the read is local, the UI updates the instant anything in that result set changes — a new message arriving, another device archiving a thread — without you wiring up a single subscription by hand.

Writing data

Mutations are functions that update the local store immediately and reconcile with the server behind the scenes. The user sees the change at interaction speed; the network round-trip happens after.

Optimistic mutation

async function archiveThread(z: Zero, threadId: string) {
  // applied locally right away, synced to the server after
  await z.mutate.thread.update({ id: threadId, archived: true });
}

Zero versus the field

The honest framing is that these tools solve overlapping problems with different constraints. ElectricSQL and PowerSync are built to sync an existing Postgres database and are the shortest path if that is your setup. Zero trades that Postgres-native path for backend flexibility — it slots in front of whatever API or database you already have. If ElectricSQL's founder calling 2026 "the year of the sync engine" sounds like hype, the fact that four credible options now exist for the same job suggests the category is real.

When to reach for it

Local-first is a strong fit for apps where the same user re-reads the same data constantly and latency is the felt experience — inboxes, issue trackers, dashboards, anything with a list you scroll and filter all day. It is overkill for a mostly-static marketing site or a form you submit once. The cost is a new moving piece (the sync server) and a shift in how you think about data — you stop fetching and start querying a local replica. For the right app, that shift deletes an entire layer of loading-state and cache-invalidation code. Zero reaching 1.0 means you can now make that bet on a stable API rather than a moving one.