Documentation Index Fetch the complete documentation index at: https://mintlify.com/alchemy-run/alchemy/llms.txt
Use this file to discover all available pages before exploring further.
Deployment
Alchemy makes it simple to deploy infrastructure to production. This guide covers deployment strategies, best practices, and CI/CD integration.
Basic Deployment
Deploy your application by running your alchemy.run.ts script:
This will:
Create or update resources
Save state to .alchemy/
Display resource URLs and outputs
Deployment Phases
Alchemy supports three phases:
Up Phase (Default)
Create or update resources:
bun ./alchemy.run.ts
# Or explicitly:
bun ./alchemy.run.ts --stage production
Read Phase
Read resource state without making changes:
bun ./alchemy.run.ts --read
Use read mode to inspect current infrastructure state.
Destroy Phase
Delete all resources:
bun ./alchemy.run.ts --destroy
This will permanently delete all resources in the current stage. Use with caution.
Stages
Stages allow you to deploy multiple independent environments (dev, staging, production):
Using Stages
# Development stage (default: your username)
bun ./alchemy.run.ts
# Staging stage
bun ./alchemy.run.ts --stage staging
# Production stage
bun ./alchemy.run.ts --stage production
Each stage has isolated state:
.alchemy/
my-app/
john/ # Development (your username)
state.json
staging/
state.json
production/
state.json
Environment-Specific Configuration
Use different configurations per stage:
import alchemy from "alchemy" ;
import { Worker } from "alchemy/cloudflare" ;
const app = await alchemy ( "my-app" );
const isProd = app . stage === "production" ;
const worker = await Worker ( "api" , {
entrypoint: "./src/index.ts" ,
bindings: {
LOG_LEVEL: isProd ? "error" : "debug" ,
API_URL: isProd
? "https://api.example.com"
: "https://staging-api.example.com"
}
});
console . log ( `Deployed to: ${ worker . url } ` );
await app . finalize ();
State Management
Local State (Default)
By default, Alchemy stores state locally in .alchemy/:
.alchemy/
my-app/
production/
state.json # Resource state
Local state is fine for development, but use remote state stores for CI/CD and teams.
Remote State
For production and teams, use a remote state store:
Cloudflare Durable Objects
AWS S3
import { CloudflareStateStore } from "alchemy/state" ;
const app = await alchemy ( "my-app" , {
stateStore : ( scope ) => new CloudflareStateStore ( scope )
});
When running in CI, Alchemy requires a remote state store. Set ALCHEMY_CI_STATE_STORE_CHECK=false to disable this check (not recommended).
Secrets Management
Setting Passwords
Secrets require a password for encryption:
export ALCHEMY_PASSWORD = "your-secure-password"
bun ./alchemy.run.ts
Or set it programmatically:
const app = await alchemy ( "my-app" , {
password: process . env . ALCHEMY_PASSWORD
});
Per-Stage Passwords
Use different passwords for different stages:
# Development
export ALCHEMY_PASSWORD = "dev-password"
bun ./alchemy.run.ts --stage dev
# Production
export ALCHEMY_PASSWORD = "prod-password"
bun ./alchemy.run.ts --stage production
CI/CD Integration
GitHub Actions
.github/workflows/deploy.yml
.github/workflows/preview.yml
name : Deploy
on :
push :
branches : [ main ]
jobs :
deploy :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- uses : oven-sh/setup-bun@v2
- name : Install dependencies
run : bun install
- name : Deploy to production
env :
ALCHEMY_PASSWORD : ${{ secrets.ALCHEMY_PASSWORD }}
CLOUDFLARE_API_KEY : ${{ secrets.CLOUDFLARE_API_KEY }}
CLOUDFLARE_ACCOUNT_ID : ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run : bun ./alchemy.run.ts --stage production
GitLab CI
stages :
- deploy
deploy:production :
stage : deploy
image : oven/bun:latest
only :
- main
script :
- bun install
- bun ./alchemy.run.ts --stage production
variables :
ALCHEMY_PASSWORD : $ALCHEMY_PASSWORD
CLOUDFLARE_API_KEY : $CLOUDFLARE_API_KEY
CLOUDFLARE_ACCOUNT_ID : $CLOUDFLARE_ACCOUNT_ID
CircleCI
version : 2.1
jobs :
deploy :
docker :
- image : oven/bun:latest
steps :
- checkout
- run :
name : Install dependencies
command : bun install
- run :
name : Deploy
command : bun ./alchemy.run.ts --stage production
workflows :
deploy :
jobs :
- deploy :
filters :
branches :
only : main
Deployment Strategies
Blue-Green Deployment
Deploy to a new stage, test, then switch:
bun ./alchemy.run.ts --stage green
curl https://green-my-app.workers.dev/health
Update DNS or routing to point to green stage.
bun ./alchemy.run.ts --destroy --stage blue
Canary Deployment
Gradually roll out changes:
const app = await alchemy ( "my-app" );
// Deploy canary version
if ( process . argv . includes ( "--canary" )) {
const canary = await Worker ( "api-canary" , {
entrypoint: "./src/index.ts" ,
routes: [{ pattern: "api.example.com/canary/*" }]
});
}
// Main version
const main = await Worker ( "api" , {
entrypoint: "./src/index.ts" ,
routes: [{ pattern: "api.example.com/*" }]
});
await app . finalize ();
Rollback
Quick Rollback
Destroy the current deployment and redeploy a previous version:
# Destroy current deployment
bun ./alchemy.run.ts --destroy --stage production
# Check out previous version
git checkout < previous-commi t >
# Redeploy
bun ./alchemy.run.ts --stage production
State-Based Rollback
Alchemy maintains state history. You can manually restore previous state:
# Backup current state
cp .alchemy/my-app/production/state.json .alchemy/my-app/production/state.json.backup
# Restore previous state
cp .alchemy/my-app/production/state.json.previous .alchemy/my-app/production/state.json
# Apply
bun ./alchemy.run.ts --stage production
Monitoring Deployments
Deployment Logs
Alchemy logs all resource operations:
Create Worker "my-app-production-api"
Update D1Database "my-app-production-db"
Delete R2Bucket "old-bucket"
Quiet Mode
Suppress logs in CI:
bun ./alchemy.run.ts --quiet --stage production
Or programmatically:
const app = await alchemy ( "my-app" , {
quiet: true
});
Telemetry
Alchemy sends anonymous telemetry by default. Opt out:
export ALCHEMY_TELEMETRY_DISABLED = 1
bun ./alchemy.run.ts
Or:
const app = await alchemy ( "my-app" , {
noTrack: true
});
Best Practices
Never use local state in CI/CD:
import { CloudflareStateStore } from "alchemy/state" ;
const app = await alchemy ( "my-app" , {
stateStore : ( scope ) => new CloudflareStateStore ( scope )
});
Use dedicated stages for each environment:
# Development
bun ./alchemy.run.ts --stage dev
# Staging
bun ./alchemy.run.ts --stage staging
# Production
bun ./alchemy.run.ts --stage production
Use GitHub Secrets, AWS Secrets Manager, or similar:
env :
ALCHEMY_PASSWORD : ${{ secrets.ALCHEMY_PASSWORD }}
CLOUDFLARE_API_KEY : ${{ secrets.CLOUDFLARE_API_KEY }}
Always test in staging first:
jobs :
deploy-staging :
steps :
- run : bun ./alchemy.run.ts --stage staging
- run : bun test
deploy-production :
needs : deploy-staging
steps :
- run : bun ./alchemy.run.ts --stage production
Follow a naming convention:
const app = await alchemy ( "my-company-my-app" );
// Resources: my-company-my-app-production-api
Enable Adoption for Existing Resources
When migrating to Alchemy:
const app = await alchemy ( "my-app" , {
adopt: true // Adopt existing resources
});
Multi-Region Deployment
Deploy to multiple regions:
import alchemy from "alchemy" ;
import { Worker } from "alchemy/cloudflare" ;
const regions = [ "us-east" , "us-west" , "eu-central" ];
for ( const region of regions ) {
const app = await alchemy ( `my-app- ${ region } ` , {
stage: "production"
});
const worker = await Worker ( `api- ${ region } ` , {
entrypoint: "./src/index.ts" ,
bindings: {
REGION: region
}
});
console . log ( ` ${ region } : ${ worker . url } ` );
await app . finalize ();
}
Troubleshooting
State Conflicts
If multiple deployments run simultaneously:
Error: State conflict detected
Solution: Use a state store with locking (CloudflareStateStore, S3StateStore).
Missing Credentials
Error: CLOUDFLARE_API_KEY is required
Ensure all required environment variables are set:
export CLOUDFLARE_API_KEY = your-key
export CLOUDFLARE_ACCOUNT_ID = your-id
Orphaned Resources
If resources aren’t cleaned up:
bun ./alchemy.run.ts --force --stage production
This forces a full reconciliation.
Example: Production Deployment
alchemy.run.ts
.github/workflows/deploy.yml
import "dotenv/config" ;
import alchemy from "alchemy" ;
import { Worker , D1Database , R2Bucket } from "alchemy/cloudflare" ;
import { CloudflareStateStore } from "alchemy/state" ;
import path from "node:path" ;
// Production-ready configuration
const app = await alchemy ( "my-app" , {
// Use remote state in production
stateStore : ( scope ) => new CloudflareStateStore ( scope ),
// Require password for secrets
password: process . env . ALCHEMY_PASSWORD ,
// Disable telemetry if needed
noTrack: process . env . ALCHEMY_TELEMETRY_DISABLED === "1"
});
// Infrastructure
const db = await D1Database ( "database" , {
name: ` ${ app . appName } - ${ app . stage } -db`
});
const bucket = await R2Bucket ( "storage" , {
name: ` ${ app . appName } - ${ app . stage } -storage`
});
// Application
const worker = await Worker ( "api" , {
entrypoint: path . join ( import . meta . dirname , "src" , "index.ts" ),
bindings: {
DB: db ,
BUCKET: bucket ,
API_KEY: alchemy . secret . env . API_KEY ,
LOG_LEVEL: app . stage === "production" ? "error" : "debug"
}
});
console . log ( `
Deployment complete!
Stage: ${ app . stage }
Worker: ${ worker . url }
Database: ${ db . name }
Bucket: ${ bucket . name }
` );
await app . finalize ();
Next Steps