PATTERN Cited by 1 source
Dynamic binding over static binding¶
Pattern¶
For every platform primitive that currently binds a single resource at deploy time (one Worker class, one Workflow class, one Durable Object namespace, one queue handler), ship a dynamic counterpart that binds a per-tenant resource at invocation time — loaded from a tenant-authored artefact, sandboxed, cached by tenant ID, and torn down when idle. The binding API the tenant sees is unchanged; the dispatcher is the only piece that knows about tenants.
Framed at full generality by Cloudflare:
"Every binding that Workers currently exposes is heading for a dynamic counterpart — queues where each producer ships its own handler, caches, databases, object stores, AI bindings, and MCP servers where every tenant brings their own tools. Whatever you bind to a Worker today, you will soon be able to bind dynamically: dispatched per tenant, per agent, per request, at zero idle cost." (Source: Cloudflare Dynamic Workflows.)
Shape¶
| Layer | Static binding | Dynamic binding |
|---|---|---|
| Compute | Workers | Dynamic Workers |
| Storage | Durable Objects | Durable Object Facets |
| Durable execution | Workflows | Dynamic Workflows |
| Queues | static | pre-announced |
| Caches | static | pre-announced |
| Databases | static | pre-announced |
| Object stores | static | pre-announced |
| AI bindings | static | pre-announced |
| MCP servers | static | pre-announced |
Each dynamic binding has the same internal shape (per sources/2026-05-01-cloudflare-introducing-dynamic-workflows-durable-execution-that-follows-the-tenant):
- A dispatcher (Worker Loader) that receives the invocation and decides which tenant's code to route to.
- A sandboxed tenant substrate (Dynamic Worker, Facet, etc.) that the dispatcher loads on demand.
- A wrapping binding (e.g.
wrapWorkflowBinding({ tenantId })) the tenant sees in theirenv. - An envelope that rides along with any persisted payload so the engine's replay can route back. See patterns/metadata-envelope-in-durable-payload.
When to apply¶
- You're shipping a platform where customers want their own business logic, not yours. App platforms (AI-authored tenant code), multi-tenant SaaS, CI/CD (per-repo pipeline), agents SDKs (per-agent plan), workflow-builder UIs, per- tenant extension systems.
- The per-tenant cost floor of container-per-tenant is too high for your tenancy model (thousands-of-tenants OK; millions-of-tenants not).
- You have a capability-based sandbox substrate available (otherwise you can't safely run untrusted tenant code).
- The platform engine's invocation API is additive-
compatible — you can wrap
.create()/.run()/ etc. without forking the engine.
Trade-offs¶
Upsides:
- Idle tenants cost approximately nothing.
- Tenants iterate independently of platform releases.
- Capability-based sandbox bounds blast radius per tenant.
- Platform engine stays unchanged — no new engine fork, no schema migration, no capacity-planning discontinuity. Just additive wrap-and-unwrap glue.
- The same dispatcher pattern can be reapplied to every other primitive, turning one implementation cost into a reusable template.
Downsides / open questions:
- Upgrade coupling with tenant artefacts. The dispatcher API (binding signatures, envelope format) is now a compatibility contract with every tenant that's shipped code against it. Breaking changes require migration logic in the dispatcher.
- Code-update semantics mid-invocation. For durable primitives (workflows in particular), a mid-flight tenant redeploy crosses the determinism requirement boundary. Cloudflare doesn't yet disclose how they handle this.
- Debuggability across the dispatch boundary. Tenant stacks don't cover the dispatcher. Platform stacks don't cover the tenant.
- Observability cardinality. Per-tenant logs, metrics, traces all need to be keyed by tenant ID; naive fan-out could blow up cardinality on the platform's observability substrate.
Relationship to adjacent patterns¶
- Generalises patterns/partner-managed-service-as-native-binding. The partner-managed pattern (Cloudflare ships a PlanetScale binding; tenants see it as native) is a bilateral binding between two fixed parties. Dynamic binding generalises the shape to any tenant — the partner role is swapped with a dispatcher role, and the binding is synthesised per invocation.
- Composes with concepts/capability-based-sandbox. The sandbox is the load-bearing isolation substrate; without it, dynamic binding is unsafe.
- Composes with concepts/execution-ladder. Dynamic Workers is Tier 1 of the execution ladder; the other dynamic bindings sit above it on the ladder as capability- extensions.
- Composes with patterns/metadata-envelope-in-durable-payload. For durable primitives, the envelope is the wire-format glue that keeps the dispatch alive across persistence boundaries.
Seen in¶
- sources/2026-05-01-cloudflare-introducing-dynamic-workflows-durable-execution-that-follows-the-tenant — canonicalises the pattern explicitly: three realised instances (Dynamic Workers + Durable Object Facets + Dynamic Workflows) plus a pre-announced six-binding roadmap (queues, caches, databases, object stores, AI bindings, MCP servers). "Each one is the same small amount of envelope-and-unwrap glue between the static binding you've always had and the dynamic version you can now hand to your customers."
Related¶
- systems/cloudflare-dynamic-workflows
- systems/dynamic-workers
- systems/durable-object-facets
- systems/cloudflare-workflows
- systems/cloudflare-durable-objects
- systems/cloudflare-workers
- concepts/per-tenant-dynamic-code-dispatch
- concepts/envelope-wrap-and-unwrap-metadata-routing
- concepts/byo-workflow-per-tenant
- patterns/metadata-envelope-in-durable-payload
- patterns/ci-pipeline-as-customer-authored-durable-workflow
- patterns/partner-managed-service-as-native-binding
- companies/cloudflare