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

# Rules: one writer

Last updated 29 October 2026

Check these rules before you deploy, restart or move a program that writes a database: each keeps one process in charge of it.

The examples use the connection `open()` returns, a node:sqlite `DatabaseSync`, as [Connect](https://tonbo.dev/docs/databases/connect.md) opens it.

### Run one instance per database

The last process to open a database becomes its only writer, and the commits of the one before are refused (see [When two instances run](https://tonbo.dev/docs/databases/how-it-works.md#takeover)). A rolling update starts the new pod before the old one stops, so on Kubernetes use the `Recreate` strategy, or a StatefulSet.

**Do**

```yaml
kind: Deployment
spec:
  replicas: 1
  strategy:
    type: Recreate # the old pod stops before the new one starts
```

**Don’t**

```yaml
kind: Deployment
spec:
  replicas: 1
  strategy:
    type: RollingUpdate # the default: both pods run, and one is refused
```

### When a reset says stop, stop

When the package resets a database, its statements and `synced()` throw `UrsulaResetError`, whose `action` says what to do. The action `stop`, with the kind `fenced`, means another process opened the database and writes it now. Opening it again would take it back from the instance that replaced this one, and the two would trade it in a loop (see [Ownership and fencing](https://tonbo.dev/docs/databases/internals/ownership.md#fenced)).

**Do**

```js
db.on("reset", (error) => {
  if (error.action === "stop") process.exit(1); // another process writes the database now
  // reopen or fix: stop taking work, then open() the database again
});
```

**Don’t**

```js
db.on("reset", async () => {
  db = await open("notes"); // takes the database back from the instance that replaced this one
});
```

### Keep the cache directory, and never copy it

Keep the cache directory, the `dir` option of `open()`, on a local disk that outlives the process where you can, never on a network filesystem: a restart then resumes instead of rebuilding (see [Cold starts](https://tonbo.dev/docs/databases/cold-starts.md#avoid)). Where the only disk goes with the process, as in a short-lived sandbox, the database still works: each new process rebuilds its local copy when it opens it, and must await `synced()` after each step that must survive (see [Short-lived processes](https://tonbo.dev/docs/databases/cold-starts.md#short-lived)). Never copy the directory to another host: the copy can take the database from the process that writes it now (see [Ownership and fencing](https://tonbo.dev/docs/databases/internals/ownership.md#background)). Open the database by name there instead.

**Do**

```js
// A volume that outlives the process: a restart resumes from it.
const db = await open("notes", { dir: "/var/lib/agent/tonbo-cache" });
```

**Don’t**

```shell
# A live cache directory, copied to another host.
rsync -a /var/lib/agent/tonbo-cache/ other-host:/var/lib/agent/tonbo-cache/
```
