Skip to content

CONCEPT Cited by 1 source

BYO workflow per tenant

Definition

BYO workflow per tenantbring-your-own-workflow-per-tenant — is the platform shape where the customer authors the durable run(event, step) function (or equivalent) and the platform is responsible for (a) loading the customer's code on demand, (b) running it inside a capability-based sandbox, (c) making sure the engine's durability machinery (retries, sleep, wait-for-event, hibernation, replay) continues to work unchanged.

The customer writes "plain, idiomatic" workflow code; they don't know they're being dispatched. The platform owns the engine, the dispatcher, and the sandbox; it does not own the workflow body. The workflow itself is a customer artefact — versioned in the customer's repo, ideally — that the platform treats as dynamically-loaded content.

Canonical framing

"You call wrapWorkflowBinding({ tenantId }) once, hand the result to their code as WORKFLOWS, and every workflow instance they create is automatically tagged, routed back, and executed in their sandbox. The framework owns the Worker Loader; the user owns the workflow; neither has to care about the other." (Source: Cloudflare Dynamic Workflows.)

When it applies

The shape fits whenever:

  • The workflow is different per tenant — e.g. each customer has a different onboarding flow, each repo has a different CI pipeline, each agent has a different durable plan.
  • The workflow is long-running — multi-minute to multi-day. Short synchronous request handlers rarely benefit from the dispatch hop.
  • The tenant wants to iterate on their own workflow independently of the platform's release cycle. BYO workflow per tenant lets the tenant redeploy without waiting for a platform push.
  • The platform's cost per tenant must stay near zero when idle, so container-per-tenant is too expensive.

Instances on the wiki

  • CI/CD: each repo ships .cloudflare/ci.ts with its own CIPipeline extends WorkflowEntrypoint class. Canonicalised in patterns/ci-pipeline-as-customer-authored-durable-workflow.
  • Agent platforms: each agent writes its own run(event, step) body — typically via model-generated TypeScript — and the platform runs it with full durability semantics. Composes with Project Think's fibers + sub-agents model.
  • Workflow-builder UIs: a customer builds a visual automation in the platform UI; the UI compiles it down to a run(event, step) body; the platform dispatches.
  • Per-tenant extension systems / low-code tools: a customer composes blocks in a no-code editor; the no-code engine emits a run(event, step) function the platform dispatches.
  • Multi-tenant SaaS with per-tenant business logic — every customer's business logic is, at runtime, some TypeScript the platform has never seen before.

Structural requirements

  1. A durable-execution engine that supports dynamic dispatch. The engine must accept class_name routing at invocation time, not just at deploy time. Canonicalised for Cloudflare via Dynamic Workflows.
  2. A sandboxed compute substrate. Tenant code runs with no ambient authority; capabilities are granted explicitly. See concepts/capability-based-sandbox.
  3. A tenant-code artefact store. The platform needs to fetch the tenant's latest source on demand — typically from an object store (R2, S3) or a Git-native store (Artifacts).
  4. A way to thread tenant identity across durability boundaries. When the workflow sleeps for 24 h, the tenant ID must ride along on the persisted payload. See concepts/envelope-wrap-and-unwrap-metadata-routing.
  5. A per-tenant observability path. The platform has to be able to attach a tail Worker (or equivalent) per tenant, so tenant logs are not interleaved across the cluster.

Trade-offs

Upsides:

  • Tenants can iterate at their own cadence without coupling to platform releases.
  • Cost floor per idle tenant approaches zero.
  • Failure blast radius per tenant is naturally bounded by the sandbox.
  • Per-tenant customisation without multi-tenant-if-statement sprawl in platform code.

Downsides / open questions:

  • Code-update semantics mid-workflow. If the tenant redeploys while a workflow is asleep, does the resumed run() see new code or old? Cloudflare's cache-by-ID eviction implies new code on next step, but the determinism implications for replay are unresolved.
  • Debuggability across the dispatch boundary. Tenants debugging a stuck workflow need stacks that span platform
  • dispatcher + tenant code. Traditional tools assume one process.
  • Upgrade coupling. The platform's dispatcher API shape (binding signatures, envelope format) is now a compatibility contract with every tenant. Breaking changes are expensive.
  • Tenant debuggability of persisted state. Tenants need a way to inspect the envelope (e.g. instance.status()) but only see their metadata, not the platform's. Cloudflare explicitly flags this: "don't put secrets in there."

Distinction from adjacent shapes

  • Not webhook-based integrations. Webhooks are reactive callouts to tenant HTTP endpoints; the tenant hosts the endpoint themselves. BYO workflow per tenant colocates the tenant's code on the platform's compute substrate.
  • Not plugin systems in the classic WordPress sense. Plugins typically run in the host's process with ambient authority and a revocable-cap firewall. BYO workflow per tenant starts from no-ambient-authority and grants capabilities explicitly.
  • Not code-mode. systems/code-mode is the consumption- side pattern (model writes TypeScript against typed MCP API, executed once and discarded). BYO workflow per tenant is the persistent flavour — the code is the tenant's durable artefact, expected to run many times over many days.
  • Not serverless-function-per-tenant. Serverless functions are typically single-invocation-scoped. BYO workflow per tenant expects the code to outlive any single request — it's the workflow's lifetime, possibly days, that the platform supports.

Seen in

Last updated · 438 distilled / 1,268 read