| name | alchemy-cloudflare |
| description | Alchemy IaC patterns for deploying TanStack Start apps to Cloudflare Workers with D1 databases. Use when setting up new TanStack Start projects, configuring Alchemy deployments, working with D1/Drizzle migrations, local development with Cloudflare bindings, or deploying to custom domains. |
Alchemy Cloudflare IaC
TypeScript-first Infrastructure as Code for deploying TanStack Start applications to Cloudflare Workers.
Core Concepts
- alchemy.run.ts: Infrastructure definition file (TypeScript, not YAML)
- TanStackStart resource: Wraps Worker config specifically for TanStack builds
- D1Database resource: Manages D1 with automatic Drizzle migration application
- Type inference:
typeof worker.Envprovides types without codegen - Secrets:
alchemy.secret()encrypts values withALCHEMY_PASSWORD
Quick Start
1. Install Dependencies
pnpm add alchemy @cloudflare/workers-types
2. Create alchemy.run.ts
import alchemy from "alchemy"
import { D1Database, TanStackStart } from "alchemy/cloudflare"
const app = await alchemy("my-app", {
stage: process.env.STAGE ?? "dev",
phase: process.argv.includes("--destroy") ? "destroy" : "up",
})
const db = await D1Database("my-d1", {
migrationsDir: "./drizzle", // Auto-applies Drizzle migrations
})
const worker = await TanStackStart("my-worker", {
d1Databases: { DB: db },
domains: ["my-app.com"], // Custom domain
})
export type Env = typeof worker.Env
await app.finalize()
3. Configure Vite
CRITICAL: Alchemy plugin must be FIRST in plugins array.
// app.config.ts
import { defineConfig } from "@tanstack/react-start/config"
import viteTsConfigPaths from "vite-tsconfig-paths"
import { alchemy } from "alchemy/cloudflare/tanstack-start"
export default defineConfig({
vite: {
plugins: [
alchemy(), // MUST be first
viteTsConfigPaths({ root: "./" }),
],
build: {
target: "esnext",
rollupOptions: {
external: ["node:async_hooks", "cloudflare:workers"],
},
},
},
})
4. Deploy
# Set encryption password (once)
export ALCHEMY_PASSWORD="your-secure-password"
# Deploy
bun alchemy.run.ts
# Deploy to specific stage
STAGE=prod bun alchemy.run.ts
# Destroy resources
bun alchemy.run.ts --destroy
Local Development
# Run dev server with Cloudflare emulation
pnpm alchemy dev
What this provides:
- Full D1 database emulation (persisted in
.alchemy/{app}/{stage}/) - KV, R2, Durable Objects bindings
- Same
Envtypes as production
Only required env var:
ALCHEMY_PASSWORD=your-password
D1 + Drizzle Integration
Migration Workflow
- Modify schema in
src/db/schema.ts - Generate migration:
pnpm drizzle-kit generate - Deploy:
bun alchemy.run.ts(auto-applies migrations)
Accessing D1
// In server functions or loaders
import { getCloudflareContext } from "@opennextjs/cloudflare"
export async function loader() {
const { env } = await getCloudflareContext()
const db = drizzle(env.DB)
// Use db...
}
Common Patterns
Multiple Environments
const stage = process.env.STAGE ?? "dev"
const app = await alchemy("my-app", { stage })
// Conditional resources
const domains = stage === "prod"
? ["app.com", "www.app.com"]
: [`${stage}.app.com`]
await TanStackStart("worker", { domains })
Secrets Management
// In alchemy.run.ts
const worker = await TanStackStart("worker", {
vars: {
PUBLIC_API_URL: "https://api.example.com",
},
secretTextBindings: {
AUTH_SECRET: alchemy.secret(process.env.AUTH_SECRET!),
STRIPE_KEY: alchemy.secret(process.env.STRIPE_KEY!),
},
})
KV Namespace
import { KVNamespace, TanStackStart } from "alchemy/cloudflare"
const sessions = await KVNamespace("sessions")
await TanStackStart("worker", {
kvNamespaces: { SESSIONS: sessions },
})
Troubleshooting
"cloudflare:workers" resolve error
Add to vite config:
rollupOptions: {
external: ["node:async_hooks", "cloudflare:workers"],
}
"Route files should not import @/db"
Server functions must be in src/server-fns/ files, not inline in route files. Routes can only import and call server functions.
D1 not persisting locally
Check .alchemy/{app}/{stage}/ directory exists. Ensure ALCHEMY_PASSWORD is set.
Migration not applying
Verify migrationsDir points to correct directory (where .sql files are).
References
- references/vite-config.md - Complete Vite configuration example
- references/alchemy-run.md - Full alchemy.run.ts example with all resources