Local Development
Alchemy’s development mode provides a powerful local development experience for Cloudflare Workers, featuring hot reloading, local resource emulation, and seamless integration with remote Cloudflare services.
Note: Development mode is currently in beta. Some features may not work as expected.
Overview
Section titled “Overview”To run Alchemy in development mode, use the --dev
flag when running your alchemy.run.ts
script:
bun run alchemy.run.ts --dev
npx tsx alchemy.run.ts --dev
pnpm tsx alchemy.run.ts --dev
yarn tsx alchemy.run.ts --dev
This starts Alchemy in development mode, which will:
- Emulate Cloudflare Workers and associated resources locally using Miniflare
- Hot reload Workers when you make changes to your code
Watching Your Alchemy Configuration
Section titled “Watching Your Alchemy Configuration”Alchemy does not watch your alchemy.run.ts
file for changes. To automatically apply changes to your configuration, you can the watch mode associated with your runtime environment. For example:
# Using bun's watch modebun run --watch alchemy.run.ts
# Using Node.js watch modenpx tsx --watch alchemy.run.ts
# Using pnpm watch modepnpm tsx --watch alchemy.run.ts
# Using yarn watch modeyarn tsx --watch alchemy.run.ts
Development mode is enabled automatically when the --watch
flag is detected.
Programmatic Configuration
Section titled “Programmatic Configuration”You can also enable dev mode programmatically by setting the dev
option:
const app = await alchemy("my-app", { dev: true,});
Configuration
Section titled “Configuration”When running in dev mode, Alchemy runs your Cloudflare Workers locally using Miniflare, and will be available on a randomly selected port. You can specify the port by setting the port
property on the Worker
resource:
const worker = await Worker("my-worker", { entrypoint: "worker.ts", dev: { port: 3000, },});
console.log(worker.url); // http://localhost:3000
Website Development
Section titled “Website Development”When using the Website
resource in development mode, you can specify a custom development command that Alchemy will run locally:
const website = await Website("my-website", { dev: { command: "npm run dev", url: "http://localhost:5173", },});
If no command is specified, Alchemy will automatically detect and run the appropriate dev command based on your project’s package manager:
bun vite dev
npx vite dev
pnpm vite dev
yarn vite dev
Vite Integration
Section titled “Vite Integration”For projects using Vite, Alchemy integrates with the Cloudflare Vite plugin to provide enhanced local development capabilities. This integration enables better support for certain binding types when running locally.
To enable Vite integration, configure your vite.config.ts
with the Cloudflare plugin:
import { cloudflare } from "@cloudflare/vite-plugin";import { defineConfig } from "vite";
export default defineConfig({ plugins: [ cloudflare({ persistState: process.env.ALCHEMY_CLOUDFLARE_PERSIST_PATH ? { path: process.env.ALCHEMY_CLOUDFLARE_PERSIST_PATH, } : undefined, }), ],});
The Vite integration provides improved support for the following binding types (marked with ✅ in the “Vite” column of the supported resources table below).
Bindings
Section titled “Bindings”By default, Alchemy emulates resources such as D1 Databases, KV Namespaces, and R2 Buckets locally.
Alchemy also supports remote bindings for select resources. For resources that allow either local or remote execution, you can set the dev
property on the resource to { remote: true }
:
const db = await D1Database("my-db", { dev: { remote: true },});
const kv = await KVNamespace("my-kv", { dev: { remote: true },});
const r2 = await R2Bucket("my-r2", { dev: { remote: true },});
Some resources only support remote execution, such as AI Gateways. These resources will automatically be run remotely, so usage will be billed the same as if you were running them in production.
Supported Resources
Section titled “Supported Resources”The following bindings are supported in dev mode:
Resource | Local | Remote | Vite |
---|---|---|---|
AI | ❌ | ✅ | ❌ |
Analytics Engine | ✅ | ❌ | ❌ |
Assets | ✅ | ❌ | ❌ |
Browser Rendering | ❌ | ✅ | ❌ |
Container | ✅ | ✅ | ❌ |
D1 Database | ✅ | ✅ | ✅ |
Dispatch Namespace | ❌ | ✅ | ❌ |
Durable Object Namespace | ✅ | ❌ | ❌ |
Hyperdrive | ✅ | ❌ | ❌ |
Images | ✅ | ✅ | ❌ |
JSON | ✅ | ❌ | ❌ |
KV Namespace | ✅ | ✅ | ✅ |
Pipeline | ✅ | ❌ | ❌ |
Queue | ✅ | ✅ | ❌ |
R2 Bucket | ✅ | ✅ | ✅ |
Secret | ✅ | ❌ | ❌ |
Secret Key | ❌ | ❌ | ❌ |
Service | ✅ | ✅ | ❌ |
Vectorize Index | ❌ | ✅ | ❌ |
Version Metadata | ✅ | ❌ | ❌ |
Workflow | ✅ | ❌ | ❌ |
Text | ✅ | ❌ | ❌ |
Limitations
Section titled “Limitations”- Hot reloading for Workers is only supported when the
entrypoint
property is set. To hot reload an inline script, you must use an external watcher to monitor youralchemy.run.ts
file. - Local Workers can push to remote queues, but cannot consume from them.
- Hyperdrive support is experimental. Hyperdrive configurations that use Cloudflare Access are not supported, and only configurations provisioned in the same
alchemy.run.ts
file will work. This is a limitation from Cloudflare that is actively being worked on. - Container bindings with
dev: { remote: true }
cannot be used as local bindings in development mode. - You may see “Connection refused” errors in the console when containers are starting up - these can be safely ignored.
Best Practices
Section titled “Best Practices”- Use local resources for development - Faster iteration and no API costs
- Test with remote resources - Validate integration before deployment
- Leverage hot reloading - Use entrypoint files for automatic rebuilds
- Monitor build output - Watch for compilation errors and warnings
- Configure Worker ports explicitly - Avoid conflicts in multi-worker setups
- Use external watchers - For automatic restarts when configuration changes