Skip to content

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):

  1. A dispatcher (Worker Loader) that receives the invocation and decides which tenant's code to route to.
  2. A sandboxed tenant substrate (Dynamic Worker, Facet, etc.) that the dispatcher loads on demand.
  3. A wrapping binding (e.g. wrapWorkflowBinding({ tenantId })) the tenant sees in their env.
  4. 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."
Last updated · 438 distilled / 1,268 read