Skip to main content
Sign In
More

SQLite + Drizzle

Use Drizzle ORM with embedded SQLite in Rivet Actors.

Use Drizzle when you want typed schema, typed queries, and generated migrations on top of actor-local SQLite.

What is Drizzle good for?

  • Typed schema: define tables in TypeScript and get typed query results.
  • Typed query builder: write SQL-like queries with autocompletion.
  • Migration workflow: generate SQL migration files from schema changes.
  • Raw SQL escape hatch: use c.db.execute(...) for direct SQLite when needed.

Project structure

Use one folder per actor database:

src/
  actors/
    todo-list/
      index.ts
      schema.ts
      drizzle.config.ts
      drizzle/
        0000_init.sql
        migrations.js
        migrations.d.ts
        meta/
          _journal.json
  • index.ts is the actor implementation.
  • drizzle/ contains files managed by drizzle-kit.
  • Commit generated migration files to source control.

Basic setup

Queries

Query builder

Use Drizzle’s typed query APIs for most reads and writes.

import { eq } from "drizzle-orm";

await c.db.insert(todos).values({ title, createdAt: Date.now() });

const rows = await c.db
  .select()
  .from(todos)
  .where(eq(todos.title, title));

Raw SQL

rivetkit/db/drizzle also exposes raw SQLite access through c.db.execute(...).

await c.db.execute(
  "CREATE INDEX IF NOT EXISTS idx_todos_created_at ON todos(created_at)",
);

Queues

Use queues for ordered mutations and keep actions read-only.

queues: {
  addTodo: queue<{ title: string }>(),
},
run: async (c) => {
  for await (const message of c.queue.iter()) {
    if (message.name === "addTodo") {
      await c.db.insert(todos).values({
        title: message.body.title,
        createdAt: Date.now(),
      });
    }
  }
},
actions: {
  getTodos: async (c) => await c.db.select().from(todos),
},

Recommendations

  • Prefer Drizzle query APIs for app code and use raw SQL for advanced SQLite features.
  • Keep one drizzle.config.ts per actor folder.
  • Re-run db:generate after schema changes and commit generated migration files.
  • Use queues for writes and actions for reads.
  • Keep related writes in one action or queue message to reduce interleaved query risk.

Read more