Durable Objects
Cloudflare Durable Objects provide a way to run stateful code on Cloudflare’s edge network.
To describe them simply (a task difficult to do justice), Durable Objects are:
- A place to store data (SQLite and KV storage).
- A single threaded sequential execution context.
- Capable of being sharded across any number of instances (think database-per-X).
Cloesce provides first class support for Durable Objects:
- Define DOs in your schema
- Generate a fully typed interface
- Use them as a Model backing
- Execute API methods within a DO’s context
Warning
Cloesce is only capable of using the modern SQLite backed Durable Objects, and does not support the legacy Durable Object storage API.
Defining a Durable Object Binding
To define a Durable Object environment binding, use the durable block:
durable MyShardedDo {
shard {
tenant: int
}
settings -> json { }
userMap -> json {
userId: int
"user/{userId}"
}
}
durable MyGlobalDo {
settings -> json { }
}
The above example defines two Durable Object bindings:
-
MyShardedDo: Any number of Durable Object instances can be created with different shard parameters. In this case, thetenantparameter is used to shard the Durable Object by tenant ID. -
MyGlobalDo: A singleton Durable Object that will always route to the same instance.
In both bindings, KV templates can be defined to generate a typed interface for interacting with the Durable Object’s KV storage.
Extending the Durable Object Class
The Cloesce Router will forward HTTP requests bound for a particular Durable Object from the Worker to the fetch method of the generated Durable Object class.
To implement custom logic for handling these requests, extend the generated Durable Object class and implement the fetch method:
import { createApp, CfEnv } from "@cloesce/backend.js";
import initMigration from "../migrations/SubRedditDo/1785712992_init.js";
export class SubRedditDo extends DurableObject<CfEnv> {
private base = createApp().durable(this, [initMigration]);
async fetch(request: Request): Promise<Response> {
return this.base.run(request);
}
}
See Building and Migrating for how those migration modules are generated.
Wrangler Configuration
A Wrangler configuration will be generated for each Durable Object binding defined in the schema:
[[durable_objects.bindings]]
class_name = "MyShardedDo"
name = "MyShardedDo"
[[durable_objects.bindings]]
class_name = "MyGlobalDo"
name = "MyGlobalDo"
[[migrations]]
new_sqlite_classes = [
"MyShardedDo",
"MyGlobalDo",
]
tag = "v1"