# Docs - **Start here** - [Introduction](/docs): Ferry is offline-first sync for TypeScript: your app reads and writes data on the device, and Ferry keeps it in step with your backend in the background. - [Quick start](/docs/quick-start): This guide builds one small app, a task list, and grows it one step at a time. Each step adds one idea. The app works from the third step on, on the device alone; the server comes in later, and the app does not change for it. - [Overview](/docs/overview): Ferry is a sync engine you add to an app you already have. The app keeps its data on the device and works from there; Ferry keeps that data in step with your backend, in the background. - Concepts - [When two devices edit the same thing](/docs/concepts/conflicts) - [useQuery or a state library?](/docs/concepts/state-libraries): Ferry's data is on the device, so any UI can read it. There are four ways to do that, and they are not rivals: they read the same local database. The difference is where your app already keeps its state. - [Undo after a restart](/docs/concepts/undo-and-storage) - **Build the app** - Client - **The basics** - [Schema](/docs/client/schema) - [The client](/docs/client/sync) - [Queries](/docs/client/queries): A query reads the rows of one table that match, in order, and stays up to date: ask it for its result at any time, or subscribe to hear when the result changes. - **Working offline** - [Transactions and undo](/docs/client/transactions-and-undo): A transaction groups writes: they apply together, sync together, and undo together. - [Status and offline](/docs/client/status-and-offline): Ferry is offline-first: the app reads and writes the device's data whether or not there is a network, and syncs when it can. sync.status says where syncing is, for the few places the UI cares. - [Storages](/docs/client/storages): A storage is where the client keeps its data on the device: the rows, the writes waiting for the server, and its own bookkeeping. Pick one per platform and pass it to createSync. - **Users and tests** - [Accounts: sign-in and sign-out](/docs/client/accounts): An app can start with no account and no server: the device holds the data. At sign-in, the same data moves to the server; at sign-out, the device starts over. Three calls cover it. - [Testing](/docs/client/testing): The client needs no server and no device to test: give it memory storage and the local() backend, which are the defaults, and it runs anywhere your tests do. - [React](/docs/react) - **Build the backend** - Server - **Set it up** - [The server](/docs/server/overview): Ferry's server is a library you mount in your backend, not a service you deploy. It runs on one route of your existing app, on your database, behind your auth. - [Auth](/docs/server/auth): Ferry has no users of its own. auth tells it who sent each request, with whatever your app already uses: a session cookie, a token, an auth library. - [Spaces](/docs/server/spaces) - [Writes from your backend](/docs/server/writes) - [Hooks](/docs/server/hooks): Hooks put your backend's rules into sync, per table: validate refuses writes, onWrite writes more in the same transaction, and afterCommit reacts once a change is saved. - **Your database** - [Stores](/docs/server/stores) - [Adopting Ferry in an existing backend](/docs/server/adoption): An existing app has its own tables, ids, ORM and migrations. Ferry fits in beside them: it keeps its own tables in your database, mirrors synced tables into yours, and takes over one feature at a time. - **Run it** - [Retention](/docs/server/retention): The server keeps a log of every change, so each device can pull what it missed. Retention drops the log's old entries, the stored answers to pushes, and the devices that stopped syncing, by itself: nothing to schedule. - [Realtime and scaling](/docs/server/realtime-and-scaling): Devices hear about each other's changes within a moment, through plain HTTP: no WebSockets, no extra service. With several server instances, one more option keeps it that fast. - [Deploy](/docs/server/deploy): Deploying Ferry is deploying your backend: the sync route ships with it, on its database. There is no service, worker or cron job to add. A few platforms need a setting or two, listed below. - [Backups](/docs/server/backups): The sync tables live in your database, so you back them up with it: snapshots, pg_dump, point-in- time recovery, VACUUM INTO or Litestream for SQLite. Restoring one takes one more step than usual, because devices may be ahead of the backup. - [Testing with a server](/docs/server/testing) - **Plug in your stack** - State libraries - [Zustand](/docs/adapters/zustand) - [Jotai](/docs/adapters/jotai) - [Legend-State](/docs/adapters/legend-state) - Examples - [Build your own stack](/docs/examples) - **Your stack** - [Supabase](/docs/examples/supabase) - [Firebase](/docs/examples/firebase) - **Your own pieces** - [Your own database](/docs/examples/own-database) - [Your own auth](/docs/examples/own-auth): Ferry has no users of its own. The server asks one question of every request, auth(request), and your code answers it: a user id, or null for a 401. Whatever already signs your users in works. - [Your own bindings](/docs/examples/own-bindings): The React hooks, the Zustand store, the Jotai atoms and the Legend-State observables are thin layers over two things every client has, so any framework or state library can have its own in a few lines: - **Backends** - [Next.js](/docs/examples/nextjs): The browser keeps the data, and one route handler of the same Next.js app is the server. It uses the schema of the Quick start. - [Hono](/docs/examples/hono): Hono passes web Requests around, so the sync route is one line, on every runtime Hono runs on. It uses the schema and server of the Quick start. - [Express](/docs/examples/express): Express runs on Node's http API, so it takes toNodeHandler(syncServer): a handler that turns the Node request into a web Request for the server, and writes the answer back. It uses the schema and server of the Quick start. - [Node.js](/docs/examples/node): No framework at all: node:http, with toNodeHandler. It uses the schema of the Quick start. Frameworks on Node's http API take the same handler; Express has its own page, Fastify and Nest are below. - [Bun](/docs/examples/bun) - [Cloudflare Workers](/docs/examples/cloudflare-workers): A Worker answers web Requests, so syncServer.fetch is the handler. There are three ways to run one: - **Data that is not synced** - [TanStack Query](/docs/examples/tanstack-query): Ferry and TanStack Query in one app, each with its own job: - [SWR](/docs/examples/swr): Ferry and SWR in one app, each with its own job: - **Reference** - [Benchmarks](/docs/benchmarks) - [Versioning](/docs/versioning): Ferry has four version numbers. They change for different reasons, and most upgrades touch only one of them.