Skip to content

Cloudflare Pages Deployment

Complete guide for deploying to Cloudflare Pages

Developer Documentation

This page contains technical information for developers. For staff operational procedures, see the Customer Service section.


Overview

Both muse-customer (ncmuse.co) and muse-admin (staff.ncmuse.co) are deployed to Cloudflare Pages. This guide covers deployment procedures, common issues, and best practices.

Key Infrastructure:

  • Platform: Cloudflare Pages + Workers
  • Customer Portal: ncmuse.co
  • Admin Portal: staff.ncmuse.co
  • Database: Cloudflare D1
  • Build Tool: Vite

Deployment Commands

Customer Portal (ncmuse.co)

bash
cd muse-customer
rm -rf dist && npm run build
npx wrangler pages deploy dist --project-name=muse-customer

Admin Portal (staff.ncmuse.co)

bash
cd muse-admin
rm -rf dist && npm run build
npx wrangler pages deploy dist --project-name=muse-admin

Always Clean Build

The rm -rf dist step is critical. Vite caches build artifacts, and deploying without cleaning will deploy stale code.


Critical: Clean Rebuild Before Deploy

Problem: Cached Build Artifacts

Symptom: After updating code, deployment still shows old content or demo data.

Root Cause: Vite caches build artifacts in the dist/ folder. If you deploy without rebuilding, you're deploying stale code.

Solution: Always clean rebuild before deployment:

bash
# ❌ WRONG - Will deploy old code
npm run build
npx wrangler pages deploy dist

# ✅ CORRECT - Always clean first
rm -rf dist && npm run build
npx wrangler pages deploy dist

Automated Deployment Script

Add this to your package.json:

json
{
  "scripts": {
    "deploy": "rm -rf dist && npm run build && npx wrangler pages deploy dist --project-name=PROJECT_NAME"
  }
}

Then deploy with:

bash
npm run deploy

Custom Domain Propagation

Preview URLs vs Custom Domains

Every deployment gets a preview URL like:

  • https://[hash].muse-customer.pages.dev
  • https://[hash].muse-admin.pages.dev

These work immediately after deployment.

Custom domains like ncmuse.co and staff.ncmuse.co take 1-2 minutes to propagate.

Testing Workflow

Step 1: Test Preview URL First

bash
# After deployment, Cloudflare shows:
 Deployment complete! Take a peek over at https://[hash].muse-customer.pages.dev

# Test this URL immediately

Step 2: Wait for Custom Domain

  • Wait 2-3 minutes for propagation
  • Hard refresh browser (Cmd+Shift+R / Ctrl+Shift+R)
  • Test in incognito window to avoid cache

Step 3: Verify Custom Domain

  • Check ncmuse.co or staff.ncmuse.co
  • Verify new changes are live

Don't Debug Too Early

If custom domain doesn't work immediately after deployment, wait 2-3 minutes before debugging. It's likely just propagation delay, not a real issue.


Environment Variables

Build-Time vs Runtime Variables

CRITICAL: Vite compiles environment variables at build time, not runtime.

bash
# ❌ WRONG - Won't update deployed app
# Just updating .env and redeploying won't work

# ✅ CORRECT - Must rebuild
1. Update .env.production
2. rm -rf dist && npm run build
3. npx wrangler pages deploy dist

Required Environment Variables

Both Portals:

  • VITE_STRIPE_PUBLISHABLE_KEY - Stripe frontend key
  • VITE_API_BASE_URL - API endpoint base URL
  • VITE_SITE_URL - Current app URL

Cloudflare Secrets (Backend):

  • STRIPE_SECRET_KEY - Stripe backend key
  • STRIPE_WEBHOOK_SECRET - Webhook signing secret
  • DB - D1 database binding

Setting Cloudflare Secrets

Secrets are set via command line:

bash
# Set a secret
npx wrangler pages secret put SECRET_NAME --project-name=PROJECT_NAME

# List secrets
npx wrangler pages secret list --project-name=PROJECT_NAME

Secrets Require Redeployment

After setting secrets, you must redeploy for them to take effect. Cloudflare Pages binds secrets at deploy time.


Database Migrations

Migration Workflow

Step 1: Add Database Binding (if new database)

In wrangler.toml:

toml
[[d1_databases]]
binding = "DB"
database_name = "your-database-name"
database_id = "[YOUR_DATABASE_ID]"

Step 2: Create Migration SQL File

sql
-- migrations/001_add_table.sql
CREATE TABLE IF NOT EXISTS new_table (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  created_at INTEGER DEFAULT (unixepoch())
);

Step 3: Test Locally

bash
# Test on local database first
npx wrangler d1 execute your-database-name --file=migrations/001_add_table.sql

Step 4: Run on Production

bash
# Deploy to production with --remote flag
npx wrangler d1 execute your-database-name --file=migrations/001_add_table.sql --remote

Step 5: Verify Immediately

bash
# Check the table was created
npx wrangler d1 execute your-database-name --command="SELECT * FROM new_table LIMIT 1" --remote

Always Use --remote Flag for Production

Without --remote, migrations only run locally. Always verify which database you're modifying.


Deployment Checklist

Pre-Deployment

  • [ ] Code reviewed and tested locally
  • [ ] All tests passing
  • [ ] Environment variables updated (if needed)
  • [ ] Database migrations prepared (if needed)
  • [ ] No secrets or API keys in code

During Deployment

  • [ ] Clean rebuild: rm -rf dist
  • [ ] Build completes without errors
  • [ ] Correct project name specified
  • [ ] Deployment shows success message

Post-Deployment

  • [ ] Test preview URL immediately
  • [ ] Verify key functionality works
  • [ ] Wait 2-3 minutes for custom domain
  • [ ] Hard refresh and test custom domain
  • [ ] Check database changes applied (if applicable)
  • [ ] Monitor for errors in Cloudflare dashboard

Common Issues

Issue: Old Code Still Showing

Cause: Didn't clean dist/ folder before rebuilding.

Fix:

bash
rm -rf dist && npm run build && npx wrangler pages deploy dist

Issue: Custom Domain Not Working

Cause: Propagation delay (1-2 minutes).

Fix: Wait 2-3 minutes, hard refresh, test in incognito.

Issue: Environment Variables Not Updating

Cause: Vite bakes variables at build time.

Fix:

  1. Update .env.production
  2. Clean rebuild
  3. Redeploy

Issue: Database Changes Not Applied

Cause: Forgot --remote flag.

Fix: Run migration again with --remote:

bash
npx wrangler d1 execute DB_NAME --file=migration.sql --remote

Issue: Secrets Not Working

Cause: Secrets require redeployment to bind.

Fix:

  1. Set secret: npx wrangler pages secret put SECRET_NAME
  2. Redeploy application

Multi-App Architecture

Why Two Separate Apps?

Muse & Co uses a dual-app architecture:

  • muse-customer - Customer-facing portal (ncmuse.co)
  • muse-admin - Staff/admin portal (staff.ncmuse.co)

Benefits:

  • Smaller bundle sizes (no admin code in customer app)
  • Independent deployments (update one without affecting other)
  • Better security (admin functions isolated)
  • Faster builds and deploys

Shared Resources

Both apps share:

  • Same D1 database (different bindings)
  • Stripe integration
  • Email service (centralized in muse-customer)

Cross-App APIs

Admin app calls customer app APIs for shared functionality (like email sending). This requires CORS configuration:

typescript
// In API endpoint
const allowedOrigins = [
  'https://ncmuse.co',
  'https://staff.ncmuse.co',
  'https://localhost:5173', // Dev
];

nodejs_compat Flag (Critical)

Next.js 14+ Requirement

MANDATORY: All Cloudflare Pages projects using Next.js 14+ must have the nodejs_compat flag.

In wrangler.toml:

toml
compatibility_flags = ["nodejs_compat"]

Without this flag:

  • Deployments fail with cryptic errors
  • Node.js built-ins don't work
  • Serverless functions break

Don't Deploy Without nodejs_compat

This flag is absolutely required for Next.js 14+. Deployments will fail without it.


Best Practices

1. Always Clean Build

bash
rm -rf dist && npm run build

2. Test Preview URL First

Don't expect custom domain to work immediately. Test the preview URL.

3. Use Deployment Scripts

Add "deploy" script to package.json to ensure consistent deployment.

4. Verify Database Migrations

Always run a SELECT query after migration to verify it worked.

5. Monitor Cloudflare Dashboard

Check for errors and performance issues after deployment.

6. Use Incognito for Testing

Avoid browser cache issues when verifying deployments.

7. Document Environment Changes

If you update environment variables, document what changed and why.



Questions? See Troubleshooting Guide or ask a senior developer.

Internal documentation for Muse & Co staff only