alchemy-cloudflare
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.
When & Why to Use This Skill
This Claude skill provides Alchemy Infrastructure as Code (IaC) patterns specifically optimized for deploying TanStack Start applications to Cloudflare Workers. It streamlines the management of Cloudflare resources like D1 databases, KV namespaces, and custom domains using a TypeScript-first approach, eliminating the need for complex YAML configurations while ensuring type safety across the entire deployment pipeline.
Use Cases
- Rapidly bootstrapping new TanStack Start projects with pre-configured Cloudflare Workers and D1 database integration.
- Automating D1 database schema updates by integrating Drizzle migrations directly into the infrastructure deployment workflow.
- Setting up local development environments that accurately emulate Cloudflare bindings (KV, R2, D1) for consistent behavior between local and production stages.
- Managing multi-environment deployments (dev, staging, prod) with secure secret encryption and conditional resource provisioning.
- Configuring custom domains and Vite-based build optimizations specifically tailored for the Cloudflare edge runtime.
| 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