After this lesson you'll be able to explain what a dispatch namespace and dynamic dispatch Worker are, upload a customer-authored script into a namespace, route to it from a gateway Worker, and state how tenant isolation and pricing actually work.
Workers for Platforms is how you let your customers deploy code onto your product — safely, cheaply, and without giving them SSH access to anything. It's Workers-on-Workers: your platform is itself a Worker, and each of your customers gets their own Worker script running underneath it, isolated by the same V8 isolate sandboxing that separates any two unrelated Workers on Cloudflare's network. You've probably used a product built on this without realizing it — most "write custom logic for your store/site/app" features on SaaS platforms are a thin UI in front of exactly this mechanism.
Three pieces, and the vocabulary matters because the docs (and this lesson) use it precisely:
dispatch_namespaces binding.The request lifecycle looks like this:
request
→ your dynamic dispatch Worker (deployed normally, has the DISPATCHER binding)
→ looks up which customer this request belongs to (subdomain, path, header, DB lookup — your logic)
→ env.DISPATCHER.get("customer-script-name")
→ that customer's isolated user Worker runs, in its own isolate
→ response bubbles back through the dispatch Worker to the caller
Cloudflare bills this whole chain as one request, not two — the hop from dispatch Worker to user Worker doesn't double-charge you the way a subrequest to an external API would.
Step 1 — create a dispatch namespace (a one-time setup step per environment):
npx wrangler dispatch-namespace create customer-scripts
npx wrangler dispatch-namespace list
Step 2 — a customer's script gets uploaded into that namespace, not deployed as a normal Worker. This is the same wrangler deploy command your platform's backend would run programmatically (e.g. from an API endpoint where customers paste or upload their code):
npx wrangler deploy customer-script.js \
--name acme-corp \
--dispatch-namespace customer-scripts
Step 3 — your gateway (dynamic dispatch) Worker is a Worker you write and deploy normally. It needs a dispatch_namespaces binding pointing at the namespace, then routes each request to the right user Worker by name:
// gateway-worker/src/index.js
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Resolve which customer this request is for — subdomain is a common pattern:
// acme-corp.yourplatform.com -> "acme-corp"
const customerId = url.hostname.split(".")[0];
const userWorker = env.DISPATCHER.get(customerId);
if (!userWorker) {
return new Response("Unknown customer", { status: 404 });
}
try {
return await userWorker.fetch(request);
} catch (err) {
// A broken customer script must not take down your gateway.
return new Response("Customer script error", { status: 502 });
}
},
};
The gateway Worker's own config needs the binding wired up so env.DISPATCHER resolves to your namespace (bindings for dispatch namespaces are configured in your Wrangler config or via the API when scripting this programmatically — see the bindings reference for the exact current syntax, since Cloudflare has been migrating config between wrangler.toml and wrangler.jsonc).
Workers for Platforms is a paid add-on, not a free-tier product — you're paying for the ability to host other people's code at all, on top of whatever your own Workers usage costs. As of this writing:
| Item | Included | Overage |
|---|---|---|
| Base plan | $25/month flat, purchased on top of the Workers Paid plan | |
| Requests | 20 million/month | $0.30 per additional million |
| CPU time | 60 million CPU-ms/month | $0.02 per additional million CPU-ms |
| Scripts (user Workers) | 1,000 scripts | $0.02 per additional script |
Notable limits baked into the pricing model: max 30 seconds of CPU time per invocation, and up to 15 minutes for Cron Trigger or Queue Consumer invocations. Subrequests within the dispatch chain (dispatch → user → any outbound call the user Worker makes) are not separately billed as extra requests — only the original inbound request is metered.
Confirm current figures before quoting them to a customer or in a proposal — Cloudflare pricing pages change without much notice.
Cloudflare Docs — Workers for Platforms is the canonical entry point for architecture, get-started guides, and configuration; check the linked pricing reference for current numbers before quoting them (verified 2026-07-03).
env includes a binding to your platform's admin D1 database (containing all customers' billing data). You pass the same env object straight through when calling a customer's user Worker. What's wrong?Dispatch namespace — the container/bucket of customer scripts (infrastructure, not code you write). Dynamic dispatch Worker — a normal Worker you write and deploy, which routes each request to the right customer script via env.DISPATCHER.get(name). User Worker — the customer's own script, uploaded into the namespace (via wrangler deploy --dispatch-namespace), which you generally do not write.