Local development
alchemy dev runs your Cloudflare stack on your machine. Workers
execute in workerd — the same runtime used in production — with
local simulators behind their bindings, websites run their
frameworks’ own dev servers with native HMR, containers run in
Docker, and code changes hot reload in milliseconds.
alchemy dev✓ Bucket (Cloudflare.R2.Bucket) created (local) ✓ DB (Cloudflare.D1.Database) created (local) ✓ Worker (Cloudflare.Worker) created (local → workerd) • http://localhost:1337 Watching for changes ...
Workers run in workerd
Section titled “Workers run in workerd”Your Worker code executes in workerd with bindings wired to the local simulators, so binding behavior matches what you deploy:
export const Cache = Cloudflare.KV.Namespace("Cache");
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.url }, Effect.gen(function* () { const kv = yield* Cloudflare.KV.ReadWriteNamespace(Cache); return { fetch: Effect.gen(function* () { yield* kv.put("greeting", "hello"); const value = yield* kv.get("greeting"); return yield* HttpServerResponse.text(value ?? ""); }).pipe(Effect.orDie), }; }).pipe(Effect.provide(Cloudflare.KV.ReadWriteNamespaceBinding)),) {}In dev, kv.put lands in a local KV simulator and the Worker
serves at http://localhost:<port>. Durable Objects run inside
the same workerd instance, cron triggers fire on their real
schedule (and the miniflare-compatible
/cdn-cgi/handler/scheduled route triggers them manually), and
because everything is a local process you can attach a debugger,
set breakpoints, and profile.
A local resource’s id is dev:-prefixed, which doubles as proof
that no cloud call ran.
Websites run their own dev servers
Section titled “Websites run their own dev servers”Every Cloudflare.Website.* resource — Vite, Next.js, Astro,
Nuxt, SvelteKit, Waku, Octane, Foldkit, StaticSite — runs its
framework’s own dev server under alchemy dev: native HMR, no
cloud resources. The site’s url is the local dev server’s
address:
const site = yield* Cloudflare.Website.Vite("Web");// dev: site.url = http://localhost:5173 — Vite's own dev server, HMR included// deploy: site.url = the deployed siteSee Frontend frameworks.
Containers run in Docker
Section titled “Containers run in Docker”A Cloudflare.Container runs as a real Docker container on your
machine, driven by its Durable Object in the local workerd:
export class Sandbox extends Cloudflare.Container< Sandbox, { ping: () => Effect.Effect<string> }>()("Sandbox") {}
export default Sandbox.make( { main: import.meta.url }, Effect.gen(function* () { return Sandbox.of({ ping: () => Effect.succeed("pong"), fetch: Effect.succeed(HttpServerResponse.text("hello")), }); }),);All three image sources work locally: main (a bundled Effect
program), context (your own Dockerfile), and image (a
pre-built remote image).
What’s emulated
Section titled “What’s emulated”These resources ship a local provider and run as simulators in dev:
| Resource | Local behavior |
|---|---|
| Workers | workerd, with hot reload and a http://localhost:<port> URL |
| Durable Objects | run inside the local workerd, including SQLite storage |
| KV Namespaces | local simulator; Node-side capability clients hit the same store |
| R2 Buckets | local simulator |
| D1 Databases | local simulator; migrations and importFiles apply on every reconcile |
| Queues + consumers | local broker with batching, retry, and dead-letter semantics |
| Hyperdrive | connects directly to your database |
| Workflows | run locally with real step semantics |
| Containers | run as Docker containers on your machine |
| Secrets Store | local store seeded with the real (Redacted-sourced) values |
| Websites | the framework’s own dev server (Vite, Astro, Next.js, Nuxt, SvelteKit, Waku, Octane, Foldkit, StaticSite) with native HMR |
Worker-only bindings are simulated too:
- Email, both directions — a
send_emailbinding persists messages as.emlfiles under.alchemy/local/email, and aPOSTto/cdn-cgi/handler/emaildrives youremail()handler with accept, reject, and reply semantics. - Browser Rendering —
env.BROWSERdrives a locally-launched headless Chrome over CDP;@cloudflare/puppeteerworks unchanged. - Images —
env.IMAGEStransforms run through sharp. - Stream — uploads land in a local video store.
- Tail consumers — a local producer’s trace events reach a local tail Worker.
- Secret keys —
secret_keyCryptoKey bindings boot locally. - Access —
dev: { access: { identity } }stubs the authenticated identity behindctx.access, so gated paths are testable without a login wall. See Protect a Worker with Access.
Resources whose provider has no local implementation (a Vectorize index, DNS records) deploy to the real cloud, into your personal stage, so a stack that mixes emulated and live-only resources just works.
Mix in the real cloud
Section titled “Mix in the real cloud”Alchemy.remote() opts any resource (or a whole scope) out of
local emulation:
// Effect-native Workerconst browser = yield* Cloudflare.Browser("BROWSER").pipe(Alchemy.remote());
// async Worker envenv: { IMAGES: Cloudflare.Images.Images("IMAGES").pipe(Alchemy.remote()) }Local and live compose into hybrid topologies. Pin a queue live and everything around it stays local — the local Worker produces real messages into the real queue, and its local consumer drains the same queue through a pull loop:
// the queue is real, even in devconst Jobs = Cloudflare.Queues.Queue("Jobs").pipe(Alchemy.remote());Your dev session sees the same traffic as staging — messages produced by deployed services or a teammate’s session land in your local handler.
Switching a resource between local and live (or dev → deploy) plans a replacement — dev state never silently becomes cloud state. See Local development for the shared semantics.
Custom port
Section titled “Custom port”export default Cloudflare.Worker("Worker", { main: import.meta.url, dev: { port: 3000, }, // ...});Where next
Section titled “Where next”- Local development — the
shared
alchemy devconcepts: hot reload,Alchemy.remote(), and dev vs deploy semantics. - Frontend frameworks —
framework dev servers under
alchemy dev. - Stages — how live-in-dev resources stay isolated per developer.
- Local Providers — build the local implementation of a resource.