> Fetch the index of every Tonbo docs page as Markdown at https://tonbo.dev/llms.txt

# Concepts

Last updated 29 October 2026

Read this before you build: it names the parts of a database that every other page refers to, in the order your program meets them.

A Tonbo database is SQLite: your program runs SQL on a SQLite file on its own disk, at the speed of SQLite. The difference is that the file is not owned by this machine: Tonbo holds the database, the file is a copy of it, and any machine that opens the database by name gets that copy.

## How it differs from the SQLite or Postgres you know

- Against a SQLite file: losing the machine loses only the commits `synced()` has not confirmed, and the program carries on from another machine.
- Against a hosted Postgres: no server stands between a statement and the data. A statement runs on the local copy and returns before its commit leaves the machine.
- One writer, on every machine: SQLite lets one connection write a file at a time, and Tonbo lets one process write a database at a time, wherever it runs.
- The same SQL, transactions and indexes. Leave the journal mode and the page size alone (see [Rules: SQLite](https://tonbo.dev/docs/databases/rules/sqlite.md)).

## A database

A SQLite database that Tonbo keeps for your account, in one region, under a name unique in the account. You create it in the console, with the CLI or through the Management API, the HTTPS API at `https://api.tonbo.dev` that creates, lists and deletes databases and streams; your program opens it by that name with an API key, from any machine (see [Manage databases](https://tonbo.dev/docs/databases/manage.md)). A database lives until you delete it, or until the expiry it was created with passes (see [Expiry](https://tonbo.dev/docs/databases/manage.md#expiry)).

## The local copy

The process that opens a database works on a local copy: a SQLite file in a cache directory on its own disk (the `dir` option of `open()`, also called the cache root), which `@tonbo/sqlite-ursula`, Tonbo’s Node.js package, builds and keeps up to date. Statements run on it at the speed of SQLite, through a node:sqlite [`DatabaseSync`](https://nodejs.org/docs/latest-v22.x/api/sqlite.html#class-databasesync). The files belong to the package: other SQLite tools cannot open them, so to read the data elsewhere, [export a copy](https://tonbo.dev/docs/databases/backups.md#export). Keep the cache directory on a disk that outlives the process, so a restart resumes instead of rebuilding (see [Requirements](https://tonbo.dev/docs/databases/connect.md#requirements)).

## A commit and synced()

A commit returns as soon as it is on this machine, and Tonbo takes it in the background. `await db.synced()` resolves once Tonbo holds every commit made before the call, in two of three replicas in different zones, and from then on the commit is durable. Until then a commit is lost with the machine, so await `synced()` before anything outside the process acts on one (see [When a commit is durable](https://tonbo.dev/docs/databases/how-it-works.md#commit)).

## The writer, and readers

One process writes a database at a time: the last one to open it. The process before it is refused from then on, even if it is still running: its commits no longer reach Tonbo and its next `synced()` throws `UrsulaResetError` with the kind `fenced`, the package’s word for a writer that another one replaced, so it should stop (see [When two instances run](https://tonbo.dev/docs/databases/how-it-works.md#takeover)). Inside the writing process, any number of connections share the database. Another process that only reads can open it read-only, as it was when it opened, without taking it from the writer (see [Read-only opens](https://tonbo.dev/docs/reference/nodejs/open.md#read-only)).

## The region and the URL

A database lives in one region, chosen when it is created and fixed for its life. Its URL names that region’s origin, your account’s id and the database’s name; opening by URL skips the lookup of the name (see [Regions and URLs](https://tonbo.dev/docs/databases/manage.md#regions)).

## Keys and tokens

An API key, which starts with `tbo_`, belongs to one account and acts as you or as an Agent of that account. Your program gives it to `open()`, which exchanges it for short-lived access tokens and keeps one fresh. Give each program a key of its own, narrowed to the databases it uses (see [What a key can reach](https://tonbo.dev/docs/platform/api-keys.md#key-scope)).

## What Tonbo keeps

Tonbo keeps each database as its latest snapshot, a compressed copy of the whole database, and the log of commits since the snapshot before it. The size limit and the storage price are stated in those terms: a database must fit a snapshot of 256 MiB compressed ([Limits](https://tonbo.dev/docs/databases/limits.md)), and its storage is that snapshot and that log ([Pricing](https://tonbo.dev/docs/databases/pricing.md)).

## Private and public

A new database is private: reads and writes need a key of the account. An owner or admin can make it public, so anyone with its URL reads it without a key; writes still need one (see [Public and private](https://tonbo.dev/docs/databases/manage.md#visibility)).

## How it reaches your program

Your program opens a database by name. Where its disk has no copy, the copy is built from Tonbo’s latest snapshot and the commits after it; where it has one, a restart starts from it instead of rebuilding. From then on statements run on the copy, and each commit goes to Tonbo in the background.

```text
  YOUR MACHINE
  +----------------------------------------+
  |  your program --SQL--> the local copy  |       a commit returns here
  +-------------------+--------------------+
                      |  in the background
                      v
  TONBO, in the database's region
  +------------+  +------------+  +------------+
  |   zone a   |  |   zone b   |  |   zone c   |   two of three hold it:
  +------------+  +------------+  +------------+   synced() resolves
                      |
                      |  open by name: the latest snapshot,
                      v  then the commits after it
  ANOTHER MACHINE, later
  +----------------------------------------+
  |  your program --SQL--> a copy, rebuilt |       it writes now; the one
  +----------------------------------------+       before it is refused
```

A commit lands on this machine first; once `synced()` resolves, two of three replicas, each in its own zone of the region, hold it, which is why another machine that opens the database by name finds every commit `synced()` confirmed.

## A database, a stream and a Machine

|  | A database | [A stream](https://tonbo.dev/docs/streams/concepts.md) | [A Machine](https://tonbo.dev/docs/machines/concepts.md) (Not open yet) |
| --- | --- | --- | --- |
| Question it answers | Where does my program’s state live, so another machine carries on from it? | How do many programs share one ordered log? | Where does my service run, asleep until a request comes? |
| Your program reaches it | SQL on a local copy, opened by name | HTTPS requests to its URL, from any language | HTTPS requests to its name |
| Who writes | One process at a time: the last one to open it | Any number of producers, each retried append once | Your program, writing its own database |
| Durable when | `synced()` resolves | The append answers `200` | In its database, once `synced()` resolves; never in memory |
