Skip to main content
Workloads

SQLite

Each actor owns its own SQLite database, giving generated apps durable relational data with no extra infrastructure.

Prefer to read code? Clone the example repository. View on GitHub

Example generated code

import { Hono } from "hono";
import { actor, setup } from "rivetkit";
import { db } from "rivetkit/db";

// Each actor owns its own SQLite database.
const notes = actor({
	db: db({
		async onMigrate(database) {
			await database.execute(`
				CREATE TABLE IF NOT EXISTS notes (
					id INTEGER PRIMARY KEY AUTOINCREMENT,
					body TEXT NOT NULL
				)
			`);
		},
	}),
	actions: {
		async add(c, body: string) {
			await c.db.execute("INSERT INTO notes (body) VALUES (?)", body);
		},
		async list(c) {
			return c.db.execute("SELECT id, body FROM notes ORDER BY id");
		},
	},
});

export const registry = setup({ use: { notes } });

const app = new Hono();
app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));
app.get("/", (c) =>
	c.json({ message: "Use the RivetKit client to add notes." }),
);

export default app;

Deploy and connect

Deploy the app, then connect to its actors from your own system:

// Connect to the actors inside the app's own Rivet namespace.
const client = createClient<typeof registry>({
	endpoint: deployment.endpoint,
	namespace: deployment.namespace,
	poolName: deployment.pool,
	token: deployment.token,
});

const notes = client.notes.getOrCreate(["shared"]);
await notes.add("Hello from the RivetKit client");
console.log(await notes.list());

deployApp() returns the endpoint, namespace, pool, and token the ordinary RivetKit client needs. See SQLite in Rivet Actors for the full database API.