Durable Object Facets: per-app SQLite for Dynamic Workers
Key Points
- Facets let Dynamic Workers export Durable Object classes at runtime
- Each facet gets an isolated SQLite-backed Durable Object storage
- Open beta now available for Workers Paid plan
Summary
Cloudflare now supports Durable Object Facets (beta), a way to dynamically load and run a Durable Object class inside a supervisor Durable Object using Dynamic Workers. Each facet gets its own SQLite-backed Durable Object storage (isolated from the supervisor), letting AI-generated or user-generated apps have persistent, ultra-low-latency state while the platform retains control for logging, billing, and limits.
Key Points
-
What it is
- A supervisor Durable Object (you write) can dynamically instantiate a Durable Object class from Dynamic Worker code as a "facet."
- Each facet receives its own SQLite database that is separate from the supervisor's database but stored together as part of the same DO instance.
-
How it works (practical flow)
- Supervisor DO uses ctx.facets.get(name, initializer) to obtain/instantiate a facet.
- In the initializer the supervisor loads a Dynamic Worker via the Dynamic Worker Loader API (loader.get/load) and extracts the exported Durable Object class (getDurableObjectClass).
- The supervisor forwards requests (facet.fetch(request)) or calls RPC into the facet; the facet uses ctx.storage.kv or ctx.storage.sql (both backed by SQLite).
- Supervisor can persist app code and codeId in its storage and pass them to the loader (example uses crypto.randomUUID()).
-
Implementation notes
- The dynamic app must export a class extending DurableObject (e.g., export class App extends DurableObject {}).
- Wrangler config needs a migrations entry with new_sqlite_classes for the supervisor (e.g., "AppRunner") and a worker_loaders binding for the loader (binding: "LOADER").
- Example local dev: npx wrangler dev. Use get() instead of load() to reuse loaded workers when appropriate.
- You can restrict network access for loaded code (e.g., globalOutbound: null) and implement logging/metrics/limits in the supervisor.
-
Caveats and availability
- Facets are in open beta and require the Workers Paid plan.
- The platform designer remains in control: you can limit object creation, add observability, and enforce billing/quotas rather than exposing raw namespace creation to untrusted code.
Actionable next steps
- Build a supervisor Durable Object that: stores app code, uses loader.get(...) to load Dynamic Workers, calls worker.getDurableObjectClass("YourClass"), and exposes facet.fetch(request).
- Update wrangler.jsonc (migrations.new_sqlite_classes and worker_loaders binding) and run npx wrangler dev for local testing.
- Implement supervisor-side limits, logging, and network restrictions before enabling user/agent-generated code in production.