Skip to content

Getting started

You can create a Worker that spins up other Workers, called Dynamic Workers, at runtime to execute code on-demand in a secure, sandboxed environment. You provide the code, choose which bindings the Dynamic Worker can access, and control whether the Dynamic Worker can reach the network.

Dynamic Workers support two loading modes:

  • load(code) creates a fresh Dynamic Worker for one-time execution.
  • get(id, callback) caches a Dynamic Worker by ID so it can stay warm across requests.

load() is best for one-time code execution, for example when using Codemode. get(id, callback) is better when the same code will receive subsequent requests, for example when you are building applications.

Try it out

Dynamic Workers Starter

Deploy to Workers

Use this "hello world" starter to get a Worker deployed that can load and execute Dynamic Workers.

Dynamic Workers Playground

Deploy to Workers

You can also deploy the Dynamic Workers Playground, where you can write or import code, bundle it at runtime with @cloudflare/worker-bundler, execute it through a Dynamic Worker, and see real-time responses and execution logs.

Configure Worker Loader

In order for a Worker to be able to create Dynamic Workers, it needs a Worker Loader binding. Unlike most Workers bindings, this binding doesn't point at any external resource in particular; it simply provides access to the Worker Loader API.

Configure it like so, in your Worker's wrangler.jsonc:

{
"worker_loaders": [
{
"binding": "LOADER",
},
],
}

Your Worker will then have access to the Worker Loader API via env.LOADER.

Run a Dynamic Worker

Use env.LOADER.load() to create a Dynamic Worker and run it:

JavaScript
export default {
async fetch(request, env) {
// Load a worker.
const worker = env.LOADER.load({
compatibilityDate: "$today",
mainModule: "src/index.js",
modules: {
"src/index.js": `
export default {
fetch(request) {
return new Response("Hello from a dynamic Worker");
},
};
`,
},
// Block all outbound network access from the Dynamic Worker.
globalOutbound: null,
});
// Get the Dynamic Worker's `export default` entrypoint.
// (A Worker can also export separate, named entrypoints.)
let entrypoint = worker.getEntrypoint();
// Forward the HTTP request to it.
return entrypoint.fetch(request);
},
};

In this example, env.LOADER.load() creates a Dynamic Worker from the code defined in modules and returns a stub that represents it.

worker.getEntrypoint().fetch(request) sends the incoming request to the Dynamic Worker's fetch() handler, which processes it and returns a response.

Reusing a Dynamic Worker across requests

If you expect to load the exact same Worker more than once, use get(id, callback) instead of load(). The id should be a unique string identifying the particular code you intend to load. When the runtime sees the same id again, it can reuse the existing Worker instead of creating a new one, if it hasn't been evicted yet.

The callback you provide will only be called if the Worker is not already loaded. This lets you skip loading the code from storage when the Worker is already running.

JavaScript
const worker = env.LOADER.get("hello-v1", async () => {
// Callback only runs if there is not already a warm
// instance available.
// Load code from storage.
let code = await env.MY_CODE_STORAGE.get("hello-v1");
// Return the same format as `env.LOADER.load()` accepts.
return {
compatibilityDate: "$today",
mainModule: "index.js",
modules: { "index.js": code },
globalOutbound: null,
};
});

Supported languages

Dynamic Workers support JavaScript (ES modules and CommonJS) and Python. The code is passed as strings in the modules object. There is no build step, so languages like TypeScript must be compiled to JavaScript before being passed to load() or get().

For the full list of supported module types, refer to the API reference.

Using TypeScript and npm dependencies

If your Dynamic Worker needs TypeScript compilation or npm dependencies, the code must be transpiled and bundled before passing to the Worker Loader.

@cloudflare/worker-bundler is a library that handles this for you. Use it to bundle source files into a format that load() and get() accept:

TypeScript
import { createWorker } from "@cloudflare/worker-bundler";
const worker = env.LOADER.get("my-worker", async () => {
const { mainModule, modules } = await createWorker({
files: {
"src/index.ts": `
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello from Hono!'));
export default app;
`,
"package.json": JSON.stringify({
dependencies: { hono: "^4.0.0" },
}),
},
});
return { mainModule, modules, compatibilityDate: "2026-01-01" };
});

createWorker() handles TypeScript compilation, dependency resolution from npm, and bundling. It returns mainModule and modules ready to pass directly to load() or get().