Cloudflare Deployment
Deploying to Cloudflare Workers
Run your Rails app on Cloudflare’s global network with D1 database.
Table of Contents
- Deploying to Cloudflare Workers
Overview
Cloudflare Workers deployment runs your application on Cloudflare’s edge network—over 300 cities worldwide. D1 is Cloudflare’s native SQLite database, purpose-built for Workers.
Use cases:
- Global applications with SQLite simplicity
- Cloudflare ecosystem integration
- Edge computing with D1’s read replicas
- Cost-effective serverless deployment
Prerequisites
- Wrangler CLI
npm i -g wrangler wrangler login - Create D1 database
wrangler d1 create myapp_productionNote the database ID from the output.
- Local environment
# .env.local D1_DATABASE_ID=xxxx-xxxx-xxxx-xxxx
Database Options
| Adapter | Service | Notes |
|---|---|---|
d1 |
Cloudflare D1 | Native SQLite, recommended |
turso |
Turso | SQLite with sync, HTTP protocol |
D1 is the primary choice for Cloudflare deployments.
Deployment
# Run migrations first
bin/juntos migrate -t cloudflare -d d1
# Deploy
bin/juntos deploy -t cloudflare -d d1
The deploy command:
- Builds the app with Cloudflare configuration
- Generates
wrangler.tomlandsrc/index.js - Verifies the build loads correctly
- Runs
wrangler deploy
Manual Deployment
If you prefer manual control:
# Build only
bin/juntos build -t cloudflare -d d1
# Deploy with Wrangler
cd dist
wrangler deploy
Generated Files
wrangler.toml
name = "myapp"
main = "src/index.js"
compatibility_date = "2026-01-01"
compatibility_flags = ["nodejs_compat"]
[[d1_databases]]
binding = "DB"
database_name = "myapp_production"
database_id = "${D1_DATABASE_ID}"
[assets]
directory = "./app/assets"
src/index.js
import { Application, Router } from '../lib/rails.js';
import '../config/routes.js';
import { migrations } from '../db/migrate/index.js';
import { Seeds } from '../db/seeds.js';
import { layout } from '../app/views/layouts/application.js';
Application.configure({
migrations: migrations,
seeds: Seeds,
layout: layout
});
export default Application.worker();
Migrations
D1 migrations run via Wrangler:
# The migrate command uses wrangler d1 execute
bin/juntos migrate -t cloudflare -d d1
This executes each pending migration against your D1 database.
Environment Variables
Set the database ID in Wrangler or Cloudflare Dashboard:
| Variable | Description |
|---|---|
D1_DATABASE_ID |
Your D1 database ID |
For secrets:
wrangler secret put API_KEY
Access in code via env.API_KEY.
D1 Specifics
Bindings
D1 is accessed via bindings, not connection strings. The Worker receives the database as env.DB:
// In the runtime
await env.DB.prepare("SELECT * FROM articles").all();
The Juntos adapter handles this automatically.
SQL Dialect
D1 uses SQLite syntax. Most Rails migrations work, but some PostgreSQL-specific features won’t:
- ✅
create_table,add_column,add_index - ✅ Standard SQL types
- ❌ Arrays, JSONB (use JSON instead)
- ❌ PostgreSQL-specific functions
Read Replicas
D1 automatically replicates reads to edge locations. Writes go to the primary. This is transparent to your application.
Static Assets
Assets in app/assets/ are served via Cloudflare’s CDN:
[assets]
directory = "./app/assets"
For Tailwind CSS, ensure the built CSS is in app/assets/builds/.
Troubleshooting
“D1_ERROR: no such table”
Migrations haven’t run:
bin/juntos migrate -t cloudflare -d d1
“Binding not found: DB”
The D1 database isn’t bound. Check wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "myapp_production"
database_id = "your-actual-id" # Not ${D1_DATABASE_ID}
Local development
Use Wrangler’s local mode:
cd dist
wrangler dev
This runs locally with a local D1 instance.
Limitations
- No filesystem — Use R2 for object storage
- No WebSockets — Use Durable Objects or external services
- CPU limits — 10-50ms CPU time per request (not wall time)
- Memory limits — 128MB per Worker
Comparison with Vercel
| Aspect | Cloudflare | Vercel |
|---|---|---|
| Database | D1 (native SQLite) | Neon/Turso/PlanetScale |
| Edge locations | 300+ cities | ~20 regions |
| Pricing model | Requests + duration | Requests + compute |
| Static assets | Integrated CDN | Integrated CDN |
| Local dev | wrangler dev |
vercel dev |
Choose Cloudflare for SQLite simplicity and maximum global distribution. Choose Vercel for PostgreSQL/MySQL compatibility or tighter Git integration.