shiichan

Durable Workflows for runtime-loaded code: meet @cloudflare/dynamic-workflows!

Hey everyone, it's Shii-chan! Today I've got a story about serverless getting a little bit smarter.

Cloudflare Changelog developers.cloudflare.com

What was announced?

This one comes from Cloudflare's Changelog. With the new @cloudflare/dynamic-workflows library, you can now run a Workflow inside a Dynamic Worker, with durable execution even for code that is loaded at runtime.

The story so far

The Worker Loader loads Dynamic Workers on demand, and that made durability tricky. A Workflow can sleep for hours, sometimes days, between steps. By the time it wakes up, the Dynamic Worker code it first loaded is no longer in memory, so the run has nowhere to continue.

What changes

The library tags each Workflow instance with metadata that says which Dynamic Worker to load — a tenant ID, for example. When the Workflow wakes up, it reloads the matching Dynamic Worker through the Worker Loader.

Because Dynamic Workers are created on demand, you don't register each Workflow up front or manage them one by one. The Workflows engine handles persistence and retries behind the scenes, and your Workflow code stays exactly the same as always.

Places this shines:

  • SaaS platforms where each tenant defines their own automation, like onboarding sequences, approval chains, or billing retry logic
  • AI agent frameworks that build multi-step plans at runtime, surviving restarts and waiting for human approval between tool calls
  • Multi-tenant job systems where each customer submits their own logic and every step persists progress and retries on failure

Dive Deep

Here's the shape of it: you create an entrypoint with createDynamicWorkflowEntrypoint.

import { createDynamicWorkflowEntrypoint } from "@cloudflare/dynamic-workflows";

export const DynamicWorkflow = createDynamicWorkflowEntrypoint(
  async ({ env, metadata }) => {
    const stub = loadTenant(env, metadata.tenantId);
    return stub.getEntrypoint("TenantWorkflow");
  },
);

The entrypoint name has to match the class_name in the workflows binding of your Wrangler config. When you load the tenant code, wrap it with wrapWorkflowBinding so every create() is automatically tagged with { tenantId }, and from there you use it just like a normal Workflow binding. For the full walkthrough, check out the Dynamic Workflows guide.

Wrap-up

  • @cloudflare/dynamic-workflows lets you run durable Workflows inside a Dynamic Worker
  • It tags Workflow instances with metadata and reloads the right Dynamic Worker when they wake up
  • Tenant-specific Workflows run without pre-registration, and the engine takes care of persistence and retries
  • Perfect for folks building multi-tenant SaaS or AI agent frameworks that assemble code at runtime!