Keep data in its database and Volume
Last updated 2 November 2026
Machines are not open yet. These pages describe Machines as they will open; until then, a create answers region_not_offered (422), “Machines are not offered in any region yet.”
Every wake starts your program fresh, so keep anything it needs across a sleep in the Machine’s own database, or as files on its Volume: open the database, answer after synced(), and stop cleanly.
The Machine’s database
Every Machine has one SQLite database, created and deleted with it. It and the Machine’s Volume are the only places a Machine keeps data durably: memory, and files outside the Volume, are gone at every wake (see What a wake starts with). tonbo database list shows it with the kind machine; it cannot be deleted on its own, and it counts toward your account’s 10,000 databases.
Requirements
A glibc-based linux/arm64 image (Debian or Ubuntu based, not Alpine) with Node.js 22.19 or later, and @tonbo/sqlite-ursula at the version these pages are checked against (see Connect from Node.js for the platforms and Durability for the version):
npm install --save-exact @tonbo/sqlite-ursula@0.11.2Only the Node.js package opens a Machine’s own database. A program in another language can still serve requests on a Machine, and keep its files on the Machine’s Volume.
Open it
The platform tells your program which database is its own, where to keep the local copy and how much committed data may wait on the Machine’s disk to be sent, and keeps the token that opens it fresh in a file kept in memory, which the package reads, so your program passes no key. The first lines of the server.js below open it. Passing maxPendingBytes as they do bounds what a crash can lose to 16 MiB of unconfirmed commits, plus one commit.
Answer after synced()
A commit returns once it is on the Machine’s disk, and is durable once await db.synced() resolves, as When a commit is durable states for every database. Answer a request only after it, so a reply never announces a commit that a crash can still lose (see the rule). A small service that does both:
import { createServer } from "node:http";
import { open } from "@tonbo/sqlite-ursula";
// On a Machine the platform always sets these: the database, its cache
// directory and how much may wait to be sent. It also keeps the token that
// opens the database fresh.
const db = await open(process.env.TONBO_DATABASE_URL, {
dir: process.env.TONBO_VFS_CACHE_DIR,
maxPendingBytes: Number(process.env.TONBO_VFS_MAX_PENDING_BYTES),
});
db.exec("CREATE TABLE IF NOT EXISTS visits(id INTEGER PRIMARY KEY, at TEXT NOT NULL)");
const server = createServer(async (req, res) => {
db.prepare("INSERT INTO visits(at) VALUES (?)").run(new Date().toISOString());
await db.synced(); // answer only once the visit is durable
const { n } = db.prepare("SELECT count(*) AS n FROM visits").get();
res.writeHead(200, { "content-type": "text/plain" }).end(`visit ${n}\n`);
});
server.listen(8080, "0.0.0.0"); // listen once the database is open
process.on("SIGTERM", async () => {
server.close(); // take no new requests
await db.synced(); // every commit is durable from here
db.close();
process.exit(0);
});Stop cleanly
Every sleep sends your program SIGTERM and stops the Machine its stop grace later (10 seconds by default). The SIGTERM handler at the end of the server.js above closes the server, awaits synced(), closes the database and exits within that time (see Stopping). A crash or the loss of a host sends no signal, so make data durable with synced() as you go, never only on SIGTERM.
After a wake
The database’s local copy lives on the Machine’s root disk, a fresh copy of the image at every wake, so each wake rebuilds the copy from Tonbo, a cold start. Open the database first, then listen, so the first request after a wake finds it ready.
Files on its Volume
A Volume is a named block volume of your account, 1 to 100 GiB, attached to one Machine at a path you choose. Your program sees an ext4 filesystem there, in any language, and finds its files as it left them at every wake. A write is durable once a flush returns, such as fsync on the file; close on its own is not one (see Data guarantees).
- A Machine has at most 1 Volume, and an account up to 10. A Volume is in one region and attaches only to a Machine there.
- A Volume is created, listed and deleted on its own. Deleting a Machine detaches its Volume and keeps it; a Volume cannot be deleted while it is attached.
- A change to which Volume a Machine has, or where, takes effect at the Machine’s next wake.
- There are no Volume snapshots, backups or resizing: a Volume is not a backup, and it does not protect against your own deletes.
- It is billed for the bytes it holds, not its size (see Pricing).
Volumes are not offered yet: a create or update that names one answers volumes_not_offered (422). Until then, keep what must last in the database.
Its limits
On a Machine, a transaction changes at most 16 MiB of pages, less than the limit for other hosts. The rest are on Limits, and how the Machine reaches its database on Database wiring.