Time Estimate: 15-20 minutes (first time) What You'll Deploy: Your React frontend to Cloudflare Pages (global CDN)
📹 Video Guide: Watch Step 8 Setup Video
Cloudflare Pages is a static site hosting platform that deploys your React app to Cloudflare's global CDN.
Why it matters:
- ⚡ Global CDN - Your frontend serves from the edge, close to users
- 🚀 Instant builds - Connected to GitHub, auto-deploys on push
- 💰 Free tier - Unlimited static requests and bandwidth
- 🔒 Automatic HTTPS - Free SSL certificates for custom domains
Your frontend will be accessible at: https://your-project.pages.dev
Before deploying, ensure you have:
✅ Backend deployed - Completed Cloudflare Workers Deployment
✅ Webhooks configured - Completed Stripe Webhooks Deployment
✅ Worker URL ready - e.g., https://your-worker.workers.dev
✅ GitHub account - Your code pushed to a GitHub repository
✅ Clerk live mode keys - Publishable key that starts with pk_live_...
This guide covers:
- Push Code to GitHub - Get your frontend repo ready
- Create Cloudflare Pages Project - Connect your repo
- Configure Build Settings - Set up Vite build
- Add Environment Variables - Connect frontend to production API
- Deploy - Trigger first build
- Verify Deployment - Test your live frontend
- Configure Custom Domain (Optional)
If your project isn't already in Git:
cd /home/mini/Documents/clerk-exp
git init
git add .
git commit -m "Initial commit - Production ready SaaS"📍 Go to: GitHub (https://github.com/new)
Create a new repository:
- Name:
your-saas-name(whatever you want) - Visibility: Private or Public (your choice)
- Don't initialize with README (you already have code)
Click "Create repository"
You can push using either HTTPS or SSH. Choose one method:
Run each command separately:
git remote add origin https://github.com/your-username/your-repo.gitgit branch -M maingit push -u origin mainIf you have SSH keys set up, use SSH instead:
git remote add origin git@github.com:your-username/your-repo.gitgit branch -M maingit push -u origin mainDon't have SSH set up? Follow GitHub's SSH key setup guide
✅ Your code is now on GitHub!
📍 Go to: Cloudflare Dashboard (https://dash.cloudflare.com)
In the left sidebar, click "Workers & Pages"
Click on the "Pages" tab - It's easy to miss! Make sure you're on the Pages tab before proceeding.
Click the "Create application" button (or "Create a project" if you have no projects yet)
Click "Connect to Git"
If this is your first time:
- Click "Connect GitHub"
- Authorize Cloudflare to access your GitHub account
- Choose which repositories to allow access (select your repo or all repos)
- Click "Install & Authorize"
You'll be redirected back to Cloudflare.
You should now see a list of your GitHub repositories.
Find and select your repository (the one you just pushed to)
Click "Begin setup"
You'll see a form with build settings. Fill them in:
Project name: your-saas-name (this will be your subdomain: your-saas-name.pages.dev)
Production branch: main (or master if that's your default branch)
Framework preset: Select "Vite" from the dropdown
Build command:
npm run build
Build output directory:
dist
Root directory (path):
frontend-v2
frontend-v2 folder, not the root. If you forget this, the build will fail.
Before proceeding, verify:
- ✅ Framework preset: Vite
- ✅ Build command:
npm run build - ✅ Build output directory:
dist - ✅ Root directory:
frontend-v2
On the same setup page, scroll down to "Environment variables (advanced)"
Click "Add variable"
Variable name:
VITE_CLERK_PUBLISHABLE_KEY
Value:
pk_live_abc123...
Where to get it:
- Go to Clerk Dashboard (https://dashboard.clerk.com)
- Select your application
- Click API Keys
- Toggle to Production mode (top-right)
- Copy Publishable key (starts with
pk_live_...)
Click "Add variable"
Click "Add variable" again
Variable name:
VITE_API_URL
Value:
https://your-worker.workers.dev
Example:
https://pan-api-abc123.workers.dev
Click "Add variable"
You should now see both variables listed:
- ✅
VITE_CLERK_PUBLISHABLE_KEY=pk_live_... - ✅
VITE_API_URL=https://your-worker.workers.dev
Click the "Save and Deploy" button at the bottom
Cloudflare will now:
- Clone your repository
- Install dependencies (
npm install) - Run the build command (
npm run build) - Deploy the
distfolder to the CDN - Assign you a URL
You'll see a build log in real-time showing:
Cloning repository...
Installing dependencies...
Running build command...
Deploying to Cloudflare's network...
Expected build time: 2-5 minutes
When complete, you'll see:
✅ Success! Deployed to https://your-saas-name.pages.dev
Copy this URL - This is your live frontend!
Open your browser and go to: https://your-saas-name.pages.dev
You should see:
- ✅ Your landing page loads
- ✅ Pricing cards display correctly
- ✅ Sign up/sign in buttons work
- Click "Sign Up"
- Enter your email and create an account
- Verify email (if required by Clerk)
- You should be redirected to the dashboard
✅ If this works - Your frontend is correctly connected to Clerk production!
In your dashboard:
- You should see your current tier (likely "Free")
- You should see usage counter
- Click "Make Request" or whatever triggers your API
- Verify the request succeeds
✅ If this works - Your frontend is correctly connected to your backend API!
- Click "Upgrade Plan" (or similar button)
- Select a paid tier
- You should be redirected to Stripe Checkout
- DON'T complete payment yet - Just verify Checkout loads
✅ If Checkout loads - Your integration is working end-to-end!
Clerk needs to know which domains are allowed to make authentication requests. You need to add your production frontend URL.
📍 Go to: Clerk Dashboard → [Your App] → API Keys
Direct link format: https://dashboard.clerk.com/apps/[your-app-id]/api-keys
Scroll down to "Allowed origins" section
Click "Add origin"
Add your Pages URL:
https://your-saas-name.pages.dev
Click "Save"
Go back to your live site and try signing up or signing in again.
✅ Should work without CORS errors now!
Now test the complete production flow:
- Sign up with a new email (or use existing account)
- Go to dashboard
- Verify tier shows "Free"
- Verify usage counter is at 0
- Make API requests (whatever triggers your API)
- Verify usage counter increments
- Make requests until you hit your free tier limit (e.g., 10 requests)
- Verify you get an error when limit is exceeded
✅ Usage tracking is working!
- Click "Upgrade Plan"
- Select a paid tier (Pro, Enterprise, etc.)
- Complete Stripe Checkout:
- Use a real card OR
- Use a 100% coupon if you set one up
- After payment, return to dashboard
- Refresh the page (to refresh JWT)
- Verify your tier updated
✅ Full subscription flow is working!
- Click "Manage Billing" in dashboard
- Verify Stripe Customer Portal loads
- Verify you can view subscription details
✅ Customer portal is working!
Cloudflare Pages automatically deploys when you push to GitHub:
- Push to
mainbranch → Deploys to production - Push to other branches → Creates preview deployment
Make a small change to your frontend:
cd frontend-v2
# Make a small change (edit a text string, etc.)
git add .
git commit -m "Test auto-deploy"
git push origin main📍 Go to: Cloudflare Dashboard → Workers & Pages → Pages tab → [Your Project]
Click on the "Deployments" tab
You should see a new deployment in progress.
Expected time: 2-5 minutes
✅ Your changes go live automatically!
Instead of your-saas-name.pages.dev, use yourdomain.com or app.yourdomain.com
📍 Go to: Workers & Pages → Pages tab → [Your Project] → Custom domains
Click "Set up a custom domain"
Enter your domain:
yourdomain.com
OR
app.yourdomain.com
Click "Continue"
If your domain is managed by Cloudflare:
- Cloudflare will automatically add the DNS records
- Click "Activate domain"
- Done! ✅
If your domain is managed elsewhere (GoDaddy, Namecheap, etc.):
- Cloudflare will show you DNS records to add
- Add the CNAME record in your DNS provider
- Come back and click "Verify"
Cloudflare automatically provisions an SSL certificate for your custom domain.
Expected time: 2-10 minutes
You'll see a status indicator change from "Pending" to "Active"
Add your custom domain to Clerk:
📍 Go to: Clerk Dashboard → API Keys → Allowed origins
Click "Add origin"
https://yourdomain.com
Click "Save"
✅ Your custom domain is live!
Cause: Root directory not set to frontend-v2
Fix:
- Go to Workers & Pages → Pages → Your Project → Settings → Builds & deployments
- Scroll to "Build configuration"
- Set Root directory to:
frontend-v2 - Click "Save"
- Go to Deployments tab → Click "Retry deployment"
Cause: Build command or framework preset incorrect
Fix:
- Go to Settings → Builds & deployments
- Verify Framework preset:
Vite - Verify Build command:
npm run build - Verify Build output directory:
dist - Click "Save" → "Retry deployment"
Cause: Missing VITE_CLERK_PUBLISHABLE_KEY environment variable
Fix:
- Go to Settings → Environment variables
- Verify
VITE_CLERK_PUBLISHABLE_KEYis set - Verify it's your production key (starts with
pk_live_) - If missing or wrong, add/update it
- Go to Deployments → "Retry deployment" (env changes require rebuild)
Cause: Your Pages URL not added to Clerk allowed origins
Fix:
- Go to Clerk Dashboard → API Keys
- Scroll to "Allowed origins"
- Add:
https://your-saas-name.pages.dev - Click "Save"
- Try signing in again (may need to refresh page)
Cause: Your frontend URL not allowed by your backend
Fix:
Option 1: Allow all origins (easier, less secure)
- Your backend's CORS is already set to allow all origins by default
- This should work unless you set
ALLOWED_ORIGINS
Option 2: Whitelist specific domains (more secure)
- Update your worker secret:
wrangler secret put ALLOWED_ORIGINS
# Value: https://your-saas-name.pages.dev,https://yourdomain.com- No redeploy needed - updates immediately
Cause: Environment variables only apply to new builds, not existing deployments
Fix:
- After changing environment variables
- Go to Deployments tab
- Find the latest deployment
- Click "Retry deployment"
- Wait for build to complete
- Changes will now be live
Cause: DNS not configured correctly or SSL pending
Fix:
- Go to Custom domains in your Pages project
- Check status - Should say "Active"
- If "Pending SSL", wait 5-10 more minutes
- If "DNS Error":
- Click "View configuration"
- Verify DNS records in your DNS provider
- CNAME should point to your Pages project
- If "Verification failed":
- Check DNS propagation: https://www.whatsmydns.net
- Wait up to 24 hours for propagation
The Problem: It's easy to end up on the Workers tab instead of Pages tab.
What to watch for:
- After clicking "Workers & Pages" in sidebar
- Look at the top of the page for two tabs: "Workers" and "Pages"
- Make sure you click "Pages" tab
- If you don't see your Pages project, you're probably on the Workers tab
The Fix:
- Always check which tab you're on (Workers vs Pages)
- Bookmark the direct link after first setup
The Problem: Your frontend is in frontend-v2/ folder, not the repo root.
What happens if you forget:
- Build fails with "package.json not found"
- Or builds the wrong folder entirely
The Fix:
- ✅ Always set Root directory to
frontend-v2 - Check this setting in the initial setup AND in Settings later
- Cloudflare won't warn you if it's wrong
The Problem: You add/change env variables but they don't take effect.
What happens:
- Your site still uses old values
- New API URL doesn't work
- Clerk keys don't update
The Fix:
- ✅ After changing env variables, always trigger a new deployment
- Go to Deployments → Retry deployment
- Or push a new commit to trigger auto-deploy
The Problem: Using pk_test_ key in production.
What happens:
- Users sign up in Clerk test mode
- Test mode users don't appear in live mode
- Subscriptions fail or go to wrong Stripe mode
The Fix:
- ✅ Always use
pk_live_keys for production frontend - Verify in Clerk Dashboard → API Keys → "Production" toggle is on
- Double-check the key starts with
pk_live_
Do this:
- Create a new branch for features:
git checkout -b new-feature - Push the branch:
git push origin new-feature - Cloudflare automatically creates a preview deployment
- Test changes at:
https://abc123.your-project.pages.dev - Merge to main when ready
Why: Test changes before they go live to production.
Do this:
- After deploying, click into the deployment
- Read through the build log
- Look for warnings or errors even if build succeeded
Why: Catches issues like missing env vars, deprecated packages, or build warnings.
Do this:
- In GitHub, enable branch protection on
main - Require pull request reviews before merging
- This prevents accidental direct pushes to production
Why: Safer deployment workflow, especially with teams.
Before considering deployment complete, verify:
- Framework preset: Vite
- Build command:
npm run build - Build output directory:
dist - Root directory:
frontend-v2 - Latest deployment shows "Success"
-
VITE_CLERK_PUBLISHABLE_KEYset topk_live_... -
VITE_API_URLset to your worker URL - Both variables visible in Settings → Environment variables
- Production Pages URL added to Clerk allowed origins
- Custom domain added to allowed origins (if applicable)
- Landing page loads without errors
- Sign up flow works
- Dashboard loads and shows correct tier
- API requests succeed
- Usage tracking increments correctly
- Upgrade flow redirects to Stripe Checkout
- After upgrade, tier updates in dashboard
- Customer portal accessible
- Push to main triggers new deployment
- New deployment completes successfully
- Changes appear on live site
📍 Go to: Workers & Pages → Pages → Your Project → Deployments
You'll see:
- All deployments (production + previews)
- Build status (success/failed)
- Build duration
- Commit message
- Who triggered the deploy
- Go to Deployments tab
- Find the deployment you want to rollback to
- Click "Rollback to this deployment"
- Confirm
✅ Instant rollback - No rebuild needed.
- Go to Deployments tab
- Click on any deployment
- Scroll through build logs
- Look for errors, warnings, or useful info
- Go to Settings → Environment variables
- Click "Edit" next to a variable
- Update the value
- Click "Save"
- Go to Deployments → Retry deployment
📍 Go to: Workers & Pages → Pages → Your Project → Analytics
You'll see:
- Requests per day - Total page loads
- Data transfer - Bandwidth used
- Unique visitors - Approximate user count
Cloudflare Pages automatically optimizes:
- ✅ Gzip/Brotli compression
- ✅ HTTP/2 and HTTP/3
- ✅ Global CDN caching
- ✅ Automatic minification
Expected load times:
- First load: < 2 seconds
- Cached loads: < 500ms
| Resource | Free Limit | Overage Cost |
|---|---|---|
| Pages Builds | 500/month | $0.50 per build |
| Bandwidth | Unlimited | Free |
| Requests | Unlimited | Free |
💡 For most projects: You'll stay on free tier indefinitely.
500 builds/month = ~16 builds per day - More than enough for most workflows.
✅ Frontend deployed to Cloudflare Pages!
Your SaaS is now fully live:
- ✅ Backend API on Cloudflare Workers
- ✅ Frontend on Cloudflare Pages
- ✅ Webhooks configured for subscriptions
- ✅ Full authentication and billing working
Recommended next steps:
- Set up custom domain for professional URLs
- Monitor usage and performance in Cloudflare dashboard
- Set up error tracking (Sentry, LogRocket, etc.)
- Add Google Analytics or your preferred analytics tool
- Test thoroughly with real users
- 📖 Cloudflare Pages Documentation
- 🚀 Pages Build Configuration
- 🐛 FAQ & Troubleshooting
- 💬 Cloudflare Community
🎉 Your SaaS is live on the edge!
Users worldwide will get fast load times and reliable service thanks to Cloudflare's global network.