Bun
Bun.serve passes web Requests, so the server's fetch is the handler, and bun:sqlite is a
store with nothing to install. It uses the schema of the Quick start.
import { Database } from 'bun:sqlite';
import { bunSqlite, createSyncServer, sqliteStore } from 'ferrysync/server';
import { schema } from './schema';
const syncServer = createSyncServer({
schema,
store: sqliteStore(bunSqlite(new Database('sync.db'))),
auth: async (request) => (await getSession(request))?.userId ?? null,
});
Bun.serve({
port: 3000,
// A realtime wait is held up to 30 s with nothing sent; Bun's default closes it after 10.
idleTimeout: 40,
fetch: (request) => syncServer.fetch(request),
});Run it with bun server.ts, and point the client at http({ url: 'http://localhost:3000/sync' }):
every path answers, by its last segment.
To route by path yourself, Bun.serve takes routes instead of fetch:
routes: { '/sync/*': { POST: syncServer.fetch } }. With Hono, see Hono.
Gotchas
idleTimeoutabove 30. Without it, realtime waits are cut at 10 seconds: the client then sees a network error every 10 seconds, retries with backoff, and realtime turns slow. 40 covers the 30-second hold.- One process per SQLite file. The store takes SQLite's write lock for each write; another
process on the same file waits for it, and needs a
busy_timeoutto wait at all. For several instances, use Postgres:postgresStorewithnodePostgresorpostgresJs, see Stores. - Keep the file on a persistent disk when deploying: see Deploy.
Node.js
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.
Cloudflare Workers
A Worker answers web Requests, so syncServer.fetch is the handler. There are three ways to run one: