Production Deployment

Complete guide for deploying SonicJS to production on Cloudflare's global edge platform.


Overview

SonicJS runs on Cloudflare's global edge network, providing:

  • Cloudflare Workers - Serverless runtime at 300+ edge locations
  • D1 Database - SQLite-based distributed database at the edge
  • R2 Object Storage - S3-compatible storage for media files
  • KV Storage - Low-latency key-value storage for caching
  • Zero cold starts - Instant response times globally

Architecture

┌─────────────────────────────────────────────────────────┐
│                   Cloudflare Edge                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │   Workers    │  │  D1 Database │  │  R2 Storage  │  │
│  │  (Runtime)   │──│  (SQLite)    │  │   (Media)    │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
│         │                                   │            │
│         └───────────── KV Cache ────────────┘            │
└─────────────────────────────────────────────────────────┘

Deployment Environments

SonicJS supports three environments:

EnvironmentDatabaseR2 BucketDomain
Developmentlocal D1dev bucketlocalhost:8787
Previewshared D1preview bucketpreview.workers.dev
Productionprod D1prod bucketyourdomain.com

Prerequisites

Required Accounts

  1. Cloudflare Account

  2. Domain Name (optional but recommended)

    • Can use workers.dev subdomain for testing
    • Custom domain recommended for production

Required Tools

Install the necessary tools:

Install Tools

# Verify Node.js 18+ is installed
node --version  # Should be v18.0.0 or higher
npm --version

Login to Cloudflare

Authenticate with your Cloudflare account:

# Login to Cloudflare
wrangler login

# This will:
# 1. Open browser for authentication
# 2. Save credentials locally
# 3. Verify account access

# Verify login
wrangler whoami

Database Setup

Create Production Database

Create a new D1 database for production:

Create Database

# Create a new D1 database
wrangler d1 create sonicjs-ai

# Output example:
# ✅ Successfully created DB 'sonicjs-ai'
#
# [[d1_databases]]
# binding = "DB"
# database_name = "sonicjs-ai"
# database_id = "583c089c-1a4a-477d-9d58-06c07bf7c1d7"

Apply Database Migrations

Apply all database migrations to production:

Run Migrations

# Apply migrations to production
npm run db:migrate:prod

Verify Database Schema

Check that all tables were created:

# List tables in production database
wrangler d1 execute sonicjs-ai --env production \
  --command="SELECT name FROM sqlite_master WHERE type='table';"

# Expected tables:
# - users
# - collections
# - content
# - content_versions
# - media
# - api_tokens
# - plugins
# - plugin_routes
# - plugin_hooks

Seed Initial Data

Create an admin user and initial collections:

Seed Data

wrangler d1 execute sonicjs-ai --env production --command="
INSERT INTO users (id, email, username, first_name, last_name, role, is_active, created_at, updated_at)
VALUES (
  'admin-' || lower(hex(randomblob(16))),
  'admin@yourdomain.com',
  'admin',
  'Admin',
  'User',
  'admin',
  1,
  strftime('%s', 'now') * 1000,
  strftime('%s', 'now') * 1000
);
"

R2 Storage Setup

Create R2 Bucket

Create an R2 bucket for media storage:

Create R2 Bucket

# Create R2 bucket for production
wrangler r2 bucket create sonicjs-media-prod

# Verify creation
wrangler r2 bucket list

# Output:
# sonicjs-media-dev
# sonicjs-media-preview
# sonicjs-media-prod

Configure Custom Domain (Optional)

Set up a custom domain for public media access:

# In Cloudflare Dashboard:
# 1. Go to R2 > sonicjs-media-prod > Settings
# 2. Click "Connect Domain"
# 3. Enter: media.yourdomain.com
# 4. DNS records will be created automatically

# This allows public access to media files via:
# https://media.yourdomain.com/uploads/image.jpg

Bucket Organization

Recommended folder structure:

sonicjs-media-prod/
├── uploads/          # User uploaded media
├── avatars/          # User avatar images
├── thumbnails/       # Generated thumbnails
├── documents/        # PDF and documents
└── temp/            # Temporary files (auto-cleanup)

Supported File Types

  • Images: JPEG, PNG, GIF, WebP, SVG
  • Documents: PDF, TXT, DOC, DOCX
  • Videos: MP4, WebM, OGG, AVI, MOV
  • Audio: MP3, WAV, OGG, M4A
  • Max File Size: 50MB

KV Cache Setup

Create KV Namespace

Create a KV namespace for caching:

Create KV Namespace

# Create KV namespace for cache
wrangler kv:namespace create "CACHE_KV" --env production

# Output:
# ✅ Created namespace with id "7171ca98640e43b6b33dbff516a5a6cf"

Verify KV Access

Test KV namespace access:

# List all KV namespaces
wrangler kv:namespace list

# Test write
wrangler kv:key put --binding CACHE_KV --env production "test" "Hello"

# Test read
wrangler kv:key get --binding CACHE_KV --env production "test"

# Delete test key
wrangler kv:key delete --binding CACHE_KV --env production "test"

Cache Usage

The cache plugin uses KV for:

  • API response caching (5 min TTL)
  • Collection metadata caching (2 hour TTL)
  • Content caching (1 hour TTL)
  • Admin dashboard stats (15 min TTL)

Cache keys follow the pattern:

cache:api:collections:all
cache:api:content-list:limit:50
cache:collection-content:blog-posts:limit:50

Environment Variables

Required Secrets

Set up required secrets for production:

Configure Secrets

# Generate and set JWT secret (required)
openssl rand -base64 32 | wrangler secret put JWT_SECRET --env production

Managing Secrets

Secret Management

# List all secrets (names only, not values)
wrangler secret list --env production

Public Variables

Configure public variables in wrangler.toml:

[env.production.vars]
ENVIRONMENT = "production"
# CDN_DOMAIN = "media.yourdomain.com"
# IMAGES_ACCOUNT_ID = "your-cloudflare-account-id"
# FEATURE_NEW_EDITOR = "true"

Deployment Workflow

Pre-deployment Checks

Run these checks before deploying:

Pre-deployment

# Run all tests
npm test

Deploy to Production

Deploy your application:

Production Deployment

# Option 1: Using predeploy script (runs tests + build)
npm run predeploy && npm run deploy

Post-deployment Verification

Verify the deployment:

Verify Deployment

# Check API health
curl https://sonicjs-ai-prod.workers.dev/api/health

# Expected response:
# {
#   "status": "healthy",
#   "timestamp": "2024-01-15T12:00:00.000Z",
#   "schemas": ["users", "collections", "content", ...]
# }

Preview Deployment

Test changes in a preview environment first:

# Deploy to preview environment
wrangler deploy --env preview

# Output:
# ✅ Successfully deployed to preview
# URL: https://sonicjs-ai-preview.workers.dev

# Test the preview deployment
curl https://sonicjs-ai-preview.workers.dev/api/health

View Deployment History

# List recent deployments
wrangler deployments list --env production

# Output:
# Created       ID                          Version
# 2024-01-15    abc123def456                v1.2.3
# 2024-01-14    def456abc789                v1.2.2
# 2024-01-13    ghi789jkl012                v1.2.1

Custom Domains

Add Custom Domain

Connect your custom domain to the Worker:

Via Cloudflare Dashboard

  1. Go to Workers & Pages > sonicjs-ai-prod
  2. Click Triggers tab
  3. Click Add Custom Domain
  4. Enter: yourdomain.com
  5. Click Add Custom Domain

Via wrangler.toml

[env.production]
name = "sonicjs-ai-prod"
routes = [
  { pattern = "yourdomain.com/*", zone_name = "yourdomain.com" },
  { pattern = "www.yourdomain.com/*", zone_name = "yourdomain.com" }
]

Then deploy:

wrangler deploy --env production

Configure DNS

Cloudflare automatically creates DNS records. Verify with:

# Check DNS propagation
dig yourdomain.com

# Or using nslookup
nslookup yourdomain.com

Manual DNS configuration (if needed):

Type: AAAA
Name: @
Content: 100::
Proxy: Enabled (orange cloud)

SSL Certificate

SSL is automatic with Cloudflare:

  1. Universal SSL - Issued automatically
  2. Edge Certificates - Free, auto-renewed
  3. Full (Strict) - Recommended encryption mode

Verify SSL:

# Check certificate
curl -vI https://yourdomain.com 2>&1 | grep -i "ssl\|tls"

# Or use SSL checker
# https://www.ssllabs.com/ssltest/analyze.html?d=yourdomain.com

Force HTTPS

Ensure all traffic uses HTTPS:

// In src/index.ts
app.use('*', async (c, next) => {
  const url = new URL(c.req.url)
  if (url.protocol === 'http:') {
    url.protocol = 'https:'
    return c.redirect(url.toString(), 301)
  }
  await next()
})

Production Checklist

Use this checklist before going live:

Infrastructure

  • Production D1 database created and migrated
  • Production R2 bucket created
  • Production KV namespace created
  • All bindings configured in wrangler.toml
  • Secrets uploaded (JWT_SECRET, etc.)
  • Custom domain added and DNS configured
  • SSL certificate active and valid

Database

  • All migrations applied successfully
  • Initial data seeded (users, collections)
  • Admin user created with secure password
  • Database indexes verified
  • Backup strategy in place

Application

  • Health check endpoint responding
  • API endpoints working correctly
  • Admin panel accessible
  • Authentication system working
  • Media upload functionality tested
  • Cache system operational

Security

  • HTTPS enforced (no HTTP access)
  • Strong JWT secret configured
  • CORS properly configured
  • Security headers configured
  • Admin password is strong and unique

Performance

  • Cache headers configured
  • Static assets compressed
  • Database queries optimized
  • KV cache working correctly
  • R2 CDN domain configured

Monitoring

  • Error logging configured
  • Performance monitoring enabled
  • Uptime monitoring setup
  • Alert notifications configured
  • Log retention policy set

Monitoring

Real-time Logs

View production logs in real-time:

Log Monitoring

# Tail production logs
wrangler tail --env production

Cloudflare Analytics

Access analytics in the dashboard:

Workers & Pages > sonicjs-ai-prod > Analytics

Key metrics:

  • Requests - Total requests and errors
  • Success Rate - % of successful requests
  • Duration - P50, P95, P99 response times
  • CPU Time - Average CPU usage
  • Errors - Error count and types

Health Check Monitoring

Set up external monitoring:

# Health check endpoint
GET https://yourdomain.com/api/health

# Expected response:
{
  "status": "healthy",
  "timestamp": "2024-01-15T12:00:00.000Z",
  "schemas": ["users", "collections", "content", "media", "plugins"]
}

Recommended monitoring services:

Performance Monitoring

Every API response includes performance headers:

X-Cache-Status: HIT
X-Cache-Source: memory
X-Cache-TTL: 278
X-Response-Time: 3ms

Rollback Procedures

View Deployment History

# List recent deployments
wrangler deployments list --env production

# Output:
# Created       ID                Version
# 2024-01-15    abc123            v1.2.3  (current)
# 2024-01-14    def456            v1.2.2
# 2024-01-13    ghi789            v1.2.1

Rollback to Previous Version

Rollback

# Rollback to previous deployment
wrangler rollback --env production

# This will rollback to: v1.2.2

Rollback with Database

If the version included database migrations:

# 1. Export current database
wrangler d1 export sonicjs-ai --env production \
  --output backup-before-rollback.sql

# 2. Rollback Worker deployment
wrangler rollback --env production

# 3. Check which migrations to revert
wrangler d1 migrations list DB --env production

# Note: D1 doesn't have automatic down migrations
# Manual SQL required for schema changes

Emergency Rollback Script

#!/bin/bash
# emergency-rollback.sh

echo "Starting emergency rollback..."

# 1. Backup current state
echo "Creating backup..."
wrangler d1 export sonicjs-ai --env production \
  --output "emergency-backup-$(date +%Y%m%d-%H%M%S).sql"

# 2. Rollback deployment
echo "Rolling back deployment..."
wrangler rollback --env production

# 3. Verify health
echo "Verifying health..."
curl -f https://yourdomain.com/api/health || echo "❌ Health check failed"

echo "Rollback complete"

Troubleshooting

Database Connection Errors

Database Issues

# Error: D1_ERROR: no such table: users

Secrets Not Found

Secret Issues

# Error: Uncaught ReferenceError: JWT_SECRET is not defined

R2 Bucket Access Denied

R2 Issues

# Error: R2 bucket 'sonicjs-media-prod' not found

Performance Issues

Slow Database Queries

-- Add missing indexes
CREATE INDEX idx_content_status ON content(status);
CREATE INDEX idx_content_collection ON content(collection_id);

-- Analyze query performance
EXPLAIN QUERY PLAN SELECT * FROM content WHERE status = 'published';

Cache Not Working

# Verify cache headers
curl -I https://yourdomain.com/api/collections | grep -i cache

# Expected headers:
# X-Cache-Status: HIT
# X-Cache-Source: memory
# X-Cache-TTL: 278

Domain and SSL Issues

SSL Certificate Errors

# Check SSL status
curl -vI https://yourdomain.com 2>&1 | grep -i ssl

# Solutions:
# 1. Wait for certificate issuance (up to 24 hours)
# 2. Verify domain is proxied (orange cloud)
# 3. Check SSL/TLS mode is "Full (strict)"

Domain Not Routing

# Verify DNS
dig yourdomain.com

# Check Worker routes
wrangler routes list

# Verify route in wrangler.toml

Getting Help


Next Steps

For ongoing support, visit our Community page.

Was this page helpful?