Why Code Mode needs something lighter than containers

When agents execute AI-generated code, that code has to run somewhere isolated. Containers are the usual answer, but they bring real costs: hundreds of milliseconds to boot, hundreds of megabytes of memory, and the temptation to keep them warm and reuse them across tasks — which undercuts the security boundary you wanted in the first place. At consumer scale, where every end user might have multiple agents each writing code, containers simply don't hold up.

Cloudflare's answer is the Dynamic Worker Loader API, now in open beta for all paid Workers users. It lets a Worker instantiate a new Worker — in its own sandbox, with code supplied at runtime — on the fly.

// Have your LLM generate code like this.
let agentCode: string = `
  export default {
    async myAgent(param, env, ctx) {
      // ...
    }
  }
`;

// Get RPC stubs representing APIs the agent should be able
// to access. (This can be any Workers RPC API you define.)
let chatRoomRpcStub = ...;

// Load a worker to run the code, using the worker loader
// binding.
let worker = env.LOADER.load({
  // Specify the code.
  compatibilityDate: "2026-03-01",
  mainModule: "agent.js",
  modules: { "agent.js": agentCode },

  // Give agent access to the chat room API.
  env: { CHAT_ROOM: chatRoomRpcStub },

  // Block internet access. (You can also intercept it.)
  globalOutbound: null,
});

// Call RPC methods exported by the agent code.
await worker.getEntrypoint().myAgent(param);

The isolate advantage

Dynamic Workers run on the same mechanism that has underpinned Cloudflare Workers since launch: V8 isolates. An isolate is an instance of the V8 JavaScript engine, the same engine in Google Chrome. Start-up takes milliseconds and memory use is a few megabytes — roughly 100x faster than a container and 10x–100x more memory-efficient.

That cost profile changes what you can do. Instead of pooling sandboxes to amortize container start-up, you can spin up a fresh isolate per request, run one snippet, and discard it. There are no global caps on concurrent sandboxes or creation rates, because this is just an API to the same infrastructure that already scales Workers to millions of requests per second. A one-off Dynamic Worker typically runs on the same machine — even the same thread — as the Worker that created it, so there's no cross-network lookup for a warm sandbox. Dynamic Workers run in every Cloudflare location worldwide.

JavaScript is the point, not the catch

The trade-off versus containers is that your agent must write JavaScript. Technically Workers can use Python and WebAssembly, but for small snippets produced on demand by a model, JavaScript loads and executes far faster.

Human preferences about languages don't apply here. LLMs are fluent in every major language, with enormous JavaScript training data. And JavaScript was built for the web — designed to be sandboxed. For this job, it's the correct language.

TypeScript APIs over HTTP

For an agent to do useful work, it needs to know what APIs it can call. MCP defines schemas for flat tool calls but not for programming APIs. OpenAPI expresses REST APIs but is verbose in both schema and calling code. For JavaScript, TypeScript is the natural fit: agents know it, it's concise, and a few tokens can convey a precise API surface.

// Interface to interact with a chat room.
interface ChatRoom {
  // Get the last `limit` messages of the chat log.
  getHistory(limit: number): Promise<Message[]>;

  // Subscribe to new messages. Dispose the returned object
  // to unsubscribe.
  subscribe(callback: (msg: Message) => void): Promise<Disposable>;

  // Post a message to chat.
  post(text: string): Promise<void>;
}

type Message = {
  author: string;
  time: Date;
  text: string;
}

An equivalent OpenAPI spec would stretch far longer, and the TypeScript version is easier for both agents and humans to parse. With Dynamic Worker Loader, you can implement such a TypeScript API in your harness Worker and pass it into the Dynamic Worker as a method parameter or via the env object. The Workers Runtime automatically bridges the sandbox and harness with Cap'n Web RPC, so the agent invokes your API across the security boundary as if it were a local library.

// Thinking: The user asked me to summarize recent chat messages from Alice.
// I will filter the recent message history in code so that I only have to
// read the relevant messages.
let history = await env.CHAT_ROOM.getHistory(1000);
return history.filter(msg => msg.author == "alice");

HTTP APIs are fully supported too, via the globalOutbound option. You register a callback invoked on every outbound HTTP request, where you can inspect, rewrite, inject auth keys, respond directly, or block. That enables credential injection: the harness adds authorization credentials as requests leave the sandbox, so the agent never sees secrets and cannot leak them. Plain HTTP makes sense when an agent is calling a well-known API already in its training data, or when a REST-based library must run inside the sandbox.

But absent a compatibility requirement, TypeScript RPC interfaces win:

  • A TypeScript interface needs far fewer tokens to describe than an HTTP interface.
  • Agent code calling TypeScript interfaces uses fewer tokens than equivalent HTTP calls.
  • Because you define the wrapper interface yourself, you naturally narrow the exposed surface to exactly the capabilities you intend — for simplicity and security. HTTP filtering is harder: your proxy must fully interpret every request, including headers and parameters that may carry meaning, to decide whether to permit it. Writing a TypeScript wrapper that only implements the functions you allow is simply easier.

Security under the hood

Isolate-based sandboxes present a more complicated attack surface than hardware virtual machines. V8 security bugs are more common than hypervisor bugs, so defense-in-depth matters. Cloudflare has nearly a decade of experience hardening its isolate platform. V8 security patches go to production within hours — faster than Chrome itself. The security architecture includes a custom second-layer sandbox with dynamic tenant cordoning based on risk, extensions to the V8 sandbox leveraging hardware features like MPK, novel Spectre defenses developed with academic researchers, and code scanning that flags malicious patterns for automatic blocking or extra sandboxing. Dynamic Workers inherit all of this by default.

Helper libraries for Dynamic Workers

Code Mode

@cloudflare/codemode simplifies running model-generated code against AI tools. Its core is DynamicWorkerExecutor(), which builds a purpose-made sandbox with code normalization for common formatting errors and direct access to a globalOutbound fetcher. Set it to null for full isolation, or pass a Fetcher binding to route, intercept, or enrich outbound requests.

const executor = new DynamicWorkerExecutor({
  loader: env.LOADER,
  globalOutbound: null, // fully isolated 
});

const codemode = createCodeTool({
  tools: myTools,
  executor,
});

return generateText({
  model,
  messages,
  tools: { codemode },
});

The package also ships two server-side utilities. codeMcpServer({ server, executor }) wraps an existing MCP Server, replacing its tools with a single code() tool. openApiMcpServer({ spec, executor, request }) takes an OpenAPI spec and builds a complete MCP Server with search() and execute() tools, suited to larger APIs. Generated code runs inside Dynamic Workers, with external calls made over RPC bindings passed to the executor.

Bundling

Dynamic Workers expect pre-bundled modules. @cloudflare/worker-bundler handles that: give it source files and a package.json, and it resolves npm dependencies, bundles with esbuild, and returns the module map the Worker Loader expects.

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';
        import { cors } from 'hono/cors';

        const app = new Hono();
        app.use('*', cors());
        app.get('/', (c) => c.text('Hello from Hono!'));
        app.get('/json', (c) => c.json({ message: 'It works!' }));

        export default app;
      `,
      "package.json": JSON.stringify({
        dependencies: { hono: "^4.0.0" }
      })
    }
  });

  return { mainModule, modules, compatibilityDate: "2026-01-01" };
});

await worker.getEntrypoint().fetch(request);

It also supports full-stack apps through createApp — bundling a server Worker, client-side JavaScript, and static assets with built-in serving for content types, ETags, and SPA routing.

File manipulation

@cloudflare/shell provides a virtual filesystem inside a Dynamic Worker. Agent code calls typed methods on a state object — read, write, search, replace, diff, glob, JSON query/update, archive — with structured inputs and outputs instead of string parsing.

Storage is backed by a durable Workspace (SQLite plus R2), so files persist across executions. Coarse operations like searchFiles, replaceInFiles, and planEdits reduce RPC round-trips — one call instead of looping over individual files. Batch writes are transactional by default: if any write fails, earlier writes roll back.

import { Workspace } from "@cloudflare/shell";
import { stateTools } from "@cloudflare/shell/workers";
import { DynamicWorkerExecutor, resolveProvider } from "@cloudflare/codemode";

const workspace = new Workspace({
  sql: this.ctx.storage.sql, // Works with any DO's SqlStorage, D1, or custom SQL backend
  r2: this.env.MY_BUCKET, // large files spill to R2 automatically
  name: () => this.name   // lazy — resolved when needed, not at construction
});

// Code runs in an isolated Worker sandbox with no network access
const executor = new DynamicWorkerExecutor({ loader: env.LOADER });

// The LLM writes this code; `state.*` calls dispatch back to the host via RPC
const result = await executor.execute(
  `async () => {
    // Search across all TypeScript files for a pattern
    const hits = await state.searchFiles("src/**/*.ts", "answer");
    // Plan multiple edits as a single transaction
    const plan = await state.planEdits([
      { kind: "replace", path: "/src/app.ts",
        search: "42", replacement: "43" },
      { kind: "writeJson", path: "/src/config.json",
        value: { version: 2 } }
    ]);
    // Apply atomically — rolls back on failure
    return await state.applyEditPlan(plan);
  }`,
  [resolveProvider(stateTools(workspace))]
);

The package includes prebuilt TypeScript type declarations and a system prompt template, dropping the full state API into an LLM context in a handful of tokens.

Real-world patterns emerging

Code mode agents

Developers want agents to write and execute code against tool APIs instead of making individual tool calls one at a time. With Dynamic Workers, the LLM generates a single TypeScript function that chains multiple API calls together, runs it in a Dynamic Worker, and returns the final result to the agent. Only the output needs to stay in the context window — the intermediate steps are discarded. That means lower latency, less token consumption, and better results when the agent has a large tool surface to work with.

Cloudflare's own MCP server is built this way. It exposes the entire Cloudflare API via two tools — search and execute — in under 1,000 tokens, because the agent writes code against a typed API rather than working through hundreds of individual tool definitions.

Custom automations

Developers are also using Dynamic Workers to let agents assemble custom automations at runtime. Zite, for example, is building an app platform where users interact via a chat interface. The LLM writes TypeScript in the background to build CRUD apps, connect to services like Stripe, Airtable, and Google Calendar, and run backend logic — with no code visible to the user. Each automation runs in its own Dynamic Worker, with access limited to only the services and libraries that endpoint needs.

"To enable server-side code for Zite's LLM-generated apps, we needed an execution layer that was instant, isolated, and secure. Cloudflare's Dynamic Workers hit the mark on all three, and out-performed all of the other platforms we benchmarked for speed and library support. The NodeJS compatible runtime supported all of Zite's workflows, allowing hundreds of third party integrations, without sacrificing on startup time. Zite now services millions of execution requests daily thanks to Dynamic Workers."

Antony Toron, CTO and Co-Founder, Zite

AI-generated applications

Platforms that generate full applications from AI are another active use case. That spans customer-facing products and internal prototypes. With Dynamic Workers, each app can be spun up on demand and returned to cold storage until it's invoked again. Fast startup times keep previews snappy during active development, and platforms can block or intercept any network requests the generated code makes to keep it safe to run.

Pricing and availability

Dynamic Workers are priced at $0.002 per unique Worker loaded per day, on top of standard Worker CPU time and invocation charges. For AI "code mode" scenarios where every Worker is a unique one-off, that works out to $0.002 per Worker loaded, plus CPU and invocations — typically negligible compared to the inference cost of generating the code itself. The charge is waived during the beta period. Pricing may change, so check the Dynamic Workers pricing page for current details.

Dynamic Workers are available now on the Workers Paid plan. A "hello world" starter deploys a Worker that can load and execute Dynamic Workers. For a fuller picture, the Dynamic Workers Playground lets you write or import code, bundle it at runtime with @cloudflare/worker-bundler, and execute it through a Dynamic Worker while watching real-time responses and execution logs.