RPC and SQLite storage
Configure SQLite-backed objects
Bind the class, add a newsqliteclasses migration, export it, and initialize a small schema safely.
8 minute lesson
Every Durable Object class needs two things in configuration: a namespace binding, so Workers can reach it, and a migration entry, so the platform knows the class exists and which storage backend it uses. New objects should use the SQLite storage backend through new_sqlite_classes.
Start with the class. Extend DurableObject from cloudflare:workers and create the schema in the constructor:
import { DurableObject } from 'cloudflare:workers'
export class ProjectRoom extends DurableObject {
constructor(ctx, env) {
super(ctx, env)
ctx.blockConcurrencyWhile(async () => {
this.ctx.storage.sql.exec(`
create table if not exists messages (
id integer primary key autoincrement,
author text not null,
body text not null,
created_at integer not null
)
`)
})
}
}
blockConcurrencyWhile holds all incoming events until the callback finishes, so no request can observe a half-created schema. Use it only for bounded schema setup like this. Do not make external network requests while all object concurrency is blocked — a slow or hanging fetch in there freezes every request to the object.
Then wire the class up in wrangler.jsonc:
{
"durable_objects": {
"bindings": [
{ "name": "PROJECT_ROOM", "class_name": "ProjectRoom" }
]
},
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["ProjectRoom"] }
]
}
The binding says “give Workers an env.PROJECT_ROOM namespace backed by the ProjectRoom class”. The migration says “this class is new, provision it on the SQLite backend”. Without the migration entry, wrangler deploy rejects the Worker and tells you the new class must be added to a migration — that error is the most common first-deploy stumble, and the fix is exactly this v1 entry.
Two details deserve care. The class_name must match the exported class name character for character; a typo like ProjectRooms deploys nothing useful. And the storage backend is permanent for a namespace — you cannot flip an existing class between backends with a config edit, which is why new classes should start on SQLite.
Verify the setup end to end: create a ProjectRoom class, add its binding and migration, generate types with wrangler types, and confirm the exported class name matches configuration. If wrangler deploy succeeds and the typed env.PROJECT_ROOM namespace shows up, the plumbing is right.
Lesson completed