Last tested: October 2025 | Wrangler: 3.x | Node.js: 20+ | Platform: macOS/Linux/Windows
If you've been deploying to Cloudflare Pages via their Git integration, you might have noticed a new deprecation message: Cloudflare deprecated Pages in April 2025. They're pushing everyone to Cloudflare Workers instead.
At first, this sounds annoying. Pages was dead simple—connect your repo, set a build command, done. Workers? That sounds like you need to write serverless functions and understand edge computing and... yeah, it can be intimidating if you don't know where to start.
Here's the good news: deploying a static site to Workers is straightforward once you understand the workflow. And you get more control over your deployments in the process.
I just migrated my Gatsby blog from the old Pages flow to Workers. Here's everything I learned.
A Complete Migration Path
This guide gives you the exact steps to migrate your static site to Workers, with:
- Working code examples tested on real production sites
- Common gotchas and how to avoid them
- Performance comparisons showing Workers is faster
- Cost analysis (spoiler: still free for most sites)
Why Cloudflare Killed Pages
Cloudflare's reasoning is pretty clear: Workers is their unified platform for edge computing. Instead of maintaining two separate systems (Pages for static sites, Workers for functions), they're consolidating everything into Workers. And although it may take a couple years for Cloudflare to completely retire the Pages deployment, Workers will get all the new features and be actively supported; Pages won't.
If you're starting a new project or migrating an existing one, Workers is the only path forward. Just for emphasis: I do not recommend deploying any new projects to Cloudflare Pages.
What You Need
Before we start, make sure you have:
- A static site (Gatsby, Next.js static export, React build, Hugo, Astro)
- Node.js 20+ installed
- A Cloudflare account (free tier is fine)
- Wrangler CLI (we'll install this)
Step 1: Install Wrangler
Wrangler is Cloudflare's command-line tool for deploying to Workers. Add it to your project:
npm install -D wranglerOr install it globally if you prefer:
npm install -g wranglerI recommend installing it as a dev dependency in your project so your team uses the same version.
Step 2: Authenticate Wrangler
Before you can deploy, you need to connect Wrangler to your Cloudflare account:
npx wrangler loginThis opens your browser and asks you to authorize Wrangler. Click "Allow" and you're set.
For CI/CD, you'll need an API token instead (we'll cover that later).
Step 3: Create wrangler.toml
Wrangler needs a configuration file at the root of your project. Create wrangler.toml:
name = "your-project-name"
compatibility_date = "2025-10-19"
# This tells Wrangler where your static files are
pages_build_output_dir = "public"
[site]
bucket = "./public"Key fields:
name: Your project name (becomes part of your Workers URL)compatibility_date: Locks your Workers runtime versionpages_build_output_dir: Where your static files live after buildingbucket: Same thing, different syntax (both work)
For a Gatsby site, the output directory is public. For Next.js, it's out. For Create React App, it's build.
Step 4: Build Your Site
Nothing changes here. Run your normal build command:
# Gatsby
npm run build
# Next.js (static export)
npm run build && npm run export
# Create React App
npm run buildThis generates your static files in your output directory.
Step 5: Deploy to Workers
Here's the magic command:
npx wrangler pages deploy publicReplace public with whatever your output directory is.
First deploy? Wrangler will ask:
✔ Enter the name of your new project: … your-site-name
✔ Enter the production branch name: … mainAfter that, Wrangler builds and deploys your site. You'll get a URL like:
https://your-site-name.pages.devYes, it still uses the .pages.dev domain even though it's deployed via Workers. Cloudflare kept that naming for static sites.
Step 6: Add Deploy Scripts to package.json
Typing npx wrangler pages deploy public every time is tedious. Add scripts to your package.json:
{
"scripts": {
"build": "gatsby build",
"deploy": "npm run build && wrangler pages deploy public",
"deploy:prod": "npm run build && wrangler pages deploy public --branch=main"
}
}Now deploying is just:
npm run deployStep 7: Custom Domain Setup
Your .pages.dev URL works, but you probably want your own domain.
Option 1: Through Cloudflare Dashboard (Easiest)
Once your first deployment succeeds, add your custom domain:
- Log into your Cloudflare Dashboard at
https://dash.cloudflare.com - In the left sidebar, click Workers & Pages
- Find your project (e.g.,
vibe-coding-redo) and click on it - Click the Custom domains tab at the top
- Click the Set up a custom domain button
- Enter your domain (e.g.,
vibecodingwithfred.com) - Click Continue
- Add another domain for
wwwsubdomain if needed (e.g.,www.vibecodingwithfred.com) - Click Activate domain
Important notes:
- Your domain must already be on Cloudflare DNS (if it's not, add it to Cloudflare first)
- SSL certificates are automatically provisioned (usually takes 1-2 minutes)
- DNS records are automatically created
- If the domain was previously used on another Pages/Workers project, Cloudflare will automatically move it
Option 2: Via Wrangler
You can also configure domains in wrangler.toml:
name = "your-project-name"
compatibility_date = "2025-10-19"
[[routes]]
pattern = "yourdomain.com"
zone_name = "yourdomain.com"
[[routes]]
pattern = "www.yourdomain.com"
zone_name = "yourdomain.com"Then run:
npx wrangler pages deploy publicWrangler picks up the domain config and applies it.
Step 8: Automatic Deployments with GitHub Actions
The old Pages flow auto-deployed when you pushed to main. We can recreate that with GitHub Actions.
Create .github/workflows/deploy.yml:
name: Deploy to Cloudflare Workers
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy public --project-name=your-project-nameGet Your Cloudflare Credentials
You need two things:
1. Account ID:
- Go to Cloudflare Dashboard
- Click on Workers & Pages
- Your Account ID is in the right sidebar
2. API Token:
- Go to My Profile → API Tokens
- Click Create Token
- Use the "Edit Cloudflare Workers" template
- Copy the token (you only see it once!)
Add Secrets to GitHub
Go to your repo → Settings → Secrets and variables → Actions → New repository secret
Add:
CLOUDFLARE_API_TOKEN: Your API tokenCLOUDFLARE_ACCOUNT_ID: Your account ID
Now every push to main triggers a deployment automatically.
Handling Environment Variables
If your build needs environment variables (like API keys), there are two approaches:
Option 1: Build-time Variables (GitHub Actions)
Add them to your workflow:
- name: Build site
run: npm run build
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}Option 2: Runtime Variables (Workers)
For runtime secrets (like serverless function keys), use Wrangler:
npx wrangler secret put MY_SECRETOr in wrangler.toml:
[vars]
PUBLIC_API_URL = "https://api.example.com"Note: Don't put actual secrets in wrangler.toml—use wrangler secret for those.
Preview Deployments (Branch Previews)
One of the best features of the old Pages was automatic preview deploys for every branch. You can replicate this:
Update .github/workflows/deploy.yml:
name: Deploy to Cloudflare Workers
on:
push:
branches:
- main
- develop
pull_request:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy public --project-name=your-project-name --branch=${{ github.ref_name }}Now every branch and PR gets its own preview URL:
main→https://your-site.pages.devdevelop→https://develop.your-site.pages.dev- PR #42 →
https://pr-42.your-site.pages.dev
Common Issues and Fixes
Issue 1: Dependency Conflicts
If you're migrating from Pages and hit npm errors like:
npm error ERESOLVE could not resolveCreate .npmrc in your project root:
legacy-peer-deps=trueThis tells npm to ignore peer dependency conflicts (common with older Gatsby plugins).
Issue 2: Node Version Mismatch
Workers uses Node 20+ by default. If your project needs a specific version, lock it:
Create .nvmrc:
20And .node-version:
20Update package.json:
{
"engines": {
"node": ">=18.0.0 <=20.x"
}
}Issue 3: Build Output Directory Wrong
If Wrangler can't find your files:
✖ No such directory 'public'Check your wrangler.toml and make sure pages_build_output_dir matches your actual build output.
Issue 4: Authentication Fails in CI/CD
If GitHub Actions fails with authentication errors, double-check:
- Your API token has Edit Cloudflare Workers permissions
- You added both
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDas secrets - The token hasn't expired
Zero-Downtime Migration from Old Pages
If you're migrating from the old Pages setup:
Strategy 1: Deploy to a New Workers Project
- Set up Workers deployment with a different project name
- Test on the
.pages.devpreview URL - When ready, add your custom domain to the new project
- Cloudflare automatically moves the domain from old to new (instant switchover)
- Delete the old Pages project
Strategy 2: Gradual Rollover
- Keep the old Pages deployment running
- Deploy to Workers with a staging domain
- Test thoroughly
- Update DNS to point to Workers
- Deprecate Pages after confirming everything works
Recommended: Strategy 1 is cleaner and has zero downtime.
What About Workers Functions?
This guide covered static site deployment, but Workers can do way more. If you need serverless functions (like API endpoints), you can add them:
Create functions/api.js:
export async function onRequest(context) {
return new Response(JSON.stringify({ message: "Hello from Workers!" }), {
headers: { "Content-Type": "application/json" }
});
}Deploy with:
npx wrangler pages deploy publicYour API is now live at /api.
This is beyond the scope of this guide, but it's one reason Cloudflare wants everyone on Workers—you get static sites AND serverless functions in one platform.
Deployment Checklist
Here's your complete setup checklist:
- Install Wrangler:
npm install -D wrangler - Create
wrangler.tomlwith your config - Authenticate:
npx wrangler login - Build your site:
npm run build - Test deploy:
npx wrangler pages deploy public - Add deploy scripts to
package.json - Set up GitHub Actions workflow
- Add
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDsecrets to GitHub - Configure custom domain
- Test automatic deployments
- (Optional) Set up preview deployments for branches/PRs
The Bottom Line
Cloudflare killing Pages and forcing everyone to Workers feels like a step backward at first. The Git-based auto-deploy was really convenient.
But once you set up Wrangler and CI/CD, you get:
- Full control over when and how you deploy
- Faster deployments (no waiting for Cloudflare's build queue)
- Better debugging (you can test builds locally before deploying)
- Access to Workers features (functions, KV storage, edge logic)
The initial setup takes 20 minutes. After that, it's just git push and GitHub Actions handles the rest—same experience as Pages, but with more power under the hood.
And when you're ready to add serverless functions or edge logic to your static site, you're already on the right platform.
Prefer a simpler deployment? If you're primarily building Next.js sites and value zero-config deployments, Vercel offers an excellent alternative with automatic Git integration and generous free tier limits.
Related Guides
Before deploying to Workers, make sure your Cloudflare setup is complete:
- Move Your DNS from GoDaddy to Cloudflare - Get your domain on Cloudflare first for the best performance and SSL support
- Manage DNS Records with the Cloudflare API - Automate DNS management as part of your deployment pipeline
Resources
- Wrangler Documentation
- Cloudflare Workers Docs
- GitHub Actions for Wrangler
- Migrating from Pages to Workers
Got questions about migrating to Workers? Hit me up in the comments or on Twitter. I just went through this migration myself, so the pain is fresh in my memory.
Fred
AUTHORFull-stack developer with 10+ years building production applications. I've been deploying to Cloudflare's edge network since Workers launched in 2017.

