Skip to content

Cloudflare Workers

WollyCMS runs on Cloudflare Workers with D1 (SQLite) for the database and R2 for media storage. This gives you a globally distributed CMS with no server to manage.

  • A Cloudflare account
  • Wrangler CLI installed (npm install -g wrangler)
  • The WollyCMS repository cloned locally
Terminal window
# Create the D1 database
wrangler d1 create wollycms-db
# Create the R2 bucket
wrangler r2 create wollycms-media

Note the database ID from the D1 create command — you will need it for wrangler.toml.

Copy the example and fill in your values:

Terminal window
cp wrangler.toml.example wrangler.toml
name = "wollycms"
main = "packages/server/dist-worker/worker.js"
compatibility_date = "2024-12-01"
compatibility_flags = ["nodejs_compat"]
# Serve the admin UI as static assets
[assets]
directory = "packages/admin/build-assets"
not_found_handling = "single-page-application"
run_worker_first = ["/", "/sitemap.xml", "/api/*", "/media/*"]
# D1 SQLite database
[[d1_databases]]
binding = "DB"
database_name = "wollycms-db"
database_id = "<your-d1-database-id>"
# R2 object storage for media
[[r2_buckets]]
binding = "R2_BUCKET"
bucket_name = "wollycms-media"
# Environment variables (non-secret)
[vars]
NODE_ENV = "production"
DATABASE_URL = "d1:DB"
MEDIA_STORAGE = "r2"
CORS_ORIGINS = "https://your-site.example.com"
SITE_URL = "https://your-site.example.com"
Terminal window
# Generate and set a strong JWT secret
wrangler secret put JWT_SECRET
Terminal window
# Build the Worker bundle and admin assets
npm run build:worker
# Run database migrations on D1
wrangler d1 execute wollycms-db --file=packages/server/drizzle/0000_init.sql
# Deploy to Cloudflare
wrangler deploy

In the Cloudflare dashboard:

  1. Go to Workers & Pages > your worker
  2. Click Settings > Triggers
  3. Add a custom domain (e.g., cms.example.com)

Make sure the domain’s DNS is managed by Cloudflare.

VariableRequiredDescription
JWT_SECRETYesSecret for signing JWT tokens (set as secret)
DATABASE_URLYesd1:DB for D1 binding
MEDIA_STORAGEYesr2 for R2 storage
CORS_ORIGINSYesComma-separated allowed origins
SITE_URLYesYour frontend site URL (for sitemaps, OG images)
NODE_ENVNoproduction recommended
  • No Sharp image processing: Workers does not support Sharp’s native binaries. Uploaded images are stored as originals without automatic variant generation. Use an external image transformation service or pre-process images before upload.
  • D1 size limits: D1 databases have row and database size limits. Check Cloudflare’s D1 limits for current numbers.
  • R2 egress: R2 has free egress, making it cost-effective for media serving.

Your Astro frontend is a separate deployment. For Cloudflare Workers:

Terminal window
# In your Astro frontend project
npm install @astrojs/cloudflare
astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare(),
});
# wrangler.toml for the Astro frontend
name = "my-site"
main = "dist/_worker.js"
compatibility_date = "2024-12-01"
compatibility_flags = ["nodejs_compat"]
[assets]
directory = "dist"
[vars]
CMS_API_URL = "https://cms.example.com/api/content"
Terminal window
npm run build
wrangler deploy