Local development
alchemy dev runs your stack on your machine. Your compute runs
locally (Workers in workerd, Lambda and ECS in Docker
containers), the services around it are emulated, and code
changes hot reload in milliseconds. Alchemy.remote() runs any
resource against the real cloud when you need it.
This page covers the concepts shared by every cloud. For what each cloud emulates and how, see the dedicated guides:
- Cloudflare local development — Workers in workerd; simulators for KV, R2, D1, Queues, Hyperdrive, Workflows, Containers, and the Worker binding surface (browser rendering, images, email, cron, Stream, …).
- AWS local development — Lambda and ECS in Docker containers with close to 40 emulated services (S3, DynamoDB, SQS, SNS, EventBridge, API Gateway, …), no AWS account required.
How it works
Section titled “How it works”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 ...
Three things happen:
- Emulatable services run locally — resources whose provider
ships a local implementation are created as local simulators
with
dev:-prefixed ids. No cloud calls. - Your code runs locally — Workers execute in workerd, Lambda functions and ECS tasks in Docker containers, websites on their framework’s own dev server — with bindings wired to the local simulators.
- File changes hot reload — edit your code and the running compute swaps in the new code without a redeploy.
Resources whose provider has no local implementation deploy to
the real cloud, into your personal
stage (dev_$USER by default), so your
loop never collides with teammates or prod. A stack that mixes
emulated and live-only resources just works.
Hot module reloading
Section titled “Hot module reloading”Watching for changes ... ↻ src/worker.ts changed • Rebuilding worker ... ✓ Worker reloaded in 42ms ↻ src/api.ts changed • Rebuilding worker ... ✓ Worker reloaded in 38ms
- Code changes take effect in milliseconds, not minutes
- Resources stay running across reloads — only your application code is rebuilt
Arbitrary dev processes — Vite, Next, anything with a dev server —
join the loop via Command.Dev: started by
alchemy dev, restarted when its inputs change, and a no-op on
deploy.
Local by default, live on demand
Section titled “Local by default, live on demand”In dev, emulatable resources are simulators. A local resource’s
id is dev:-prefixed, which doubles as proof that no cloud call
ran.
The local simulators reach beyond your compute’s bindings.
Node-side capability clients follow the same rule: a seed script
in an Action that writes to a
dev: KV Namespace or S3 bucket lands in the same local
simulator your Worker or Lambda reads.
Every other resource runs live in dev automatically, and
Alchemy.remote() (below) runs an emulatable resource against
the real cloud when local fidelity isn’t enough.
Debugging
Section titled “Debugging”Because your code runs locally, you can attach a debugger:
- Set breakpoints in your IDE
- Inspect variables and call stacks
- Profile performance
Running a resource live in dev
Section titled “Running a resource live in dev”Alchemy.remote() opts a resource out of local emulation — “run
this live even in dev”:
import * as Alchemy from "alchemy";
const worker = yield* Worker("Api", { ... }).pipe(Alchemy.remote());During alchemy deploy the pin is a no-op — everything is live
anyway. If a remote resource needs credentials you don’t have,
alchemy dev tells you before touching anything.
Opt out a whole scope
Section titled “Opt out a whole scope”yield* Effect.gen(function* () { const api = yield* Worker("Api", { ... }); const site = yield* Worker("Site", { ... });}).pipe(Alchemy.remote());The policy is ambient and captured at registration (like
adopt()), so everything inside the scope runs live. Resources
with no local emulation already run live in dev — remote() on
them is a no-op.
Local and live compose into hybrid topologies — a local Worker producing into a live queue whose local consumer drains it, or a local Lambda reading a live Secrets Manager secret. See the per-cloud guides for examples.
Switching is a replacement
Section titled “Switching is a replacement”When a resource moves between local and live — you deploy after a
dev session, or add/remove remote() — it’s planned as a
replacement: the new instance is created live, and the local
one (the workerd instance, the Docker container, the dev process)
is torn down. Dev state never silently becomes cloud state.
Dev vs Deploy
Section titled “Dev vs Deploy”alchemy dev |
alchemy deploy |
|
|---|---|---|
| Emulatable services | Local simulators (remote() for live) |
Deployed to cloud |
| Everything else | Deployed to cloud (personal stage) | Deployed to cloud |
| Application code | Runs locally (workerd, Docker) | Deployed to cloud |
| File watching | Hot reload on change | Manual redeploy |
| Debugging | Attach local debugger | Tail logs |
| Speed | Milliseconds | Seconds to minutes |
To automate the deploy side, see the CI guide.
Where next
Section titled “Where next”- Cloudflare local development — what runs in workerd and which bindings are simulated.
- AWS local development — the emulated AWS surface, Lambda/ECS containers, and zero-credential dev.
- CI — deploy the same stack from GitHub Actions with PR previews.
- Stages — how
dev_$USER,pr-42, andprodstay isolated. - Dev servers — run any framework dev server as a
Command.Devresource in the dev loop. - Local Providers — build the local implementation of a resource.