Two front doors, one engine

Pick how your application talks to the engine. The choice is about access shape, not about a different database:

ModeHow you connectBest forLatency
EmbeddedLink the native library; call it over the C ABI (bun:ffi / @twilldb/bun)A single app that owns the database; edge / offline; lowest latencyFunction call (no socket)
ServerConnect a Postgres client to engine-server over the wire protocolMultiple clients; existing Postgres tooling; REST via PostgRESTNetwork round-trip

Server mode is the same library, wrapped

The server is the embedded engine behind a network listener — there is no second engine. You can develop embedded and deploy as a server (or vice versa) without changing your SQL or your data.

The connection string selects the backend

Both modes open the database with a URL whose scheme selects the durable storage backend. Unknown schemes are rejected — never silently defaulted.

SchemeBackendWhat it gives you
file://path/to.dbLocalFileStoragePure-embedded, zero network. Dev, offline, edge, single-node.
s3://bucket/dbObjectStorage
(LSM + S3-CAS log)
Storage-disaggregated and scale-to-zero. Durability bottoms out on object storage; the local cache keeps reads off the network hot path.
r2://bucket/db
gs://bucket/db

Same binary, no rebuild

Switching from file:// to s3:// is a connection-string change, not a recompile. The engine and the C ABI are unchanged; only the backend behind the storage seam differs.

Connection-string anatomy

Embedded callers pass the URL to open(). Server callers use a standard Postgres URI pointing at the listener; the server itself was started with the storage URL.

// Embedded — the storage URL is the connection string
open("file://./local.db");
open("s3://my-bucket/app");      // bucket credentials come from the environment
# Server — start it with the storage URL, connect with a Postgres URI
cargo run -p twill-server -- --listen 127.0.0.1:5433 --db s3://my-bucket/app
psql "host=127.0.0.1 port=5433 user=postgres sslmode=disable"

Choosing a backend

  • SHOULD use file:// for development, tests, examples, embedded single-node apps, and edge/offline use — it needs no infrastructure and keeps the hot path entirely in-process.
  • SHOULD use s3:// / r2:// / gs:// when you want disaggregated durability and scale-to-zero: stateless compute that idles to nothing while only object-storage bytes bill at rest.
  • MAY prefer Cloudflare R2 (r2://) where egress cost matters — a cold cache reads from object storage, and R2's zero egress makes those misses structurally cheaper.

Security

  • MUST keep real bucket credentials in the environment, never in code, tests, or examples — those use file:// only.
  • MUST treat the connection string as configuration: it determines durability and single-writer fencing, both of which are security properties of the engine.

Where to next

Twill DB documentation · Licensed under AGPL-3.0. · Author