Deploying Next.js Static Sites to Cloudflare Pages
A comprehensive guide to deploying your Next.js static export applications to Cloudflare Pages for fast, secure, and cost-effective hosting.
Deploying Next.js Static Sites to Cloudflare Pages
Cloudflare Pages offers an excellent hosting solution for static sites with global CDN distribution, automatic HTTPS, and seamless Git integration. In this guide, we'll walk through deploying a Next.js application with static export to Cloudflare Pages.
Why Choose Cloudflare Pages?
Cloudflare Pages provides several advantages for hosting static sites:
- Global CDN: Your site is served from Cloudflare's global network
- Free Tier: Generous free tier with unlimited requests
- Automatic HTTPS: SSL certificates are handled automatically
- Git Integration: Deploy directly from GitHub, GitLab, or Bitbucket
- Preview Deployments: Every pull request gets a preview URL
- Edge Functions: Add server-side functionality when needed
Preparing Your Next.js App for Static Export
1. Configure Next.js for Static Export
First, update your next.config.js
to enable static export:
/** @type {import('next').NextConfig} */const nextConfig = {output: 'export',images: {unoptimized: true},trailingSlash: true,assetPrefix: process.env.NODE_ENV === 'production' ? '/your-app' : '',}module.exports = nextConfig
2. Handle Dynamic Routes
For dynamic routes, you need to generate static paths:
// app/blog/[slug]/page.tsxexport async function generateStaticParams() {const posts = await getAllPosts()return posts.map((post) => ({slug: post.slug,}))}
3. Update Image Handling
Since we're using static export, optimize your images:
// Use next/image with unoptimized flagimport Image from 'next/image'export default function MyImage() {return (<Imagesrc="/my-image.jpg"alt="Description"width={500}height={300}// unoptimized is set globally in next.config.js/>)}
Setting Up Cloudflare Pages
Method 1: Git Integration (Recommended)
-
Push your code to GitHub:
git add .git commit -m "Initial commit"git push origin main -
Connect to Cloudflare Pages:
- Go to Cloudflare Dashboard
- Navigate to Pages
- Click "Create a project"
- Connect your Git repository
-
Configure Build Settings:
Framework preset: Next.js (Static HTML Export) Build command: npm run build Build output directory: out Root directory: / (leave blank if at root)
-
Environment Variables (if needed):
NODE_ENV=production NEXT_PUBLIC_SITE_URL=https://your-domain.pages.dev
Method 2: Direct Upload
For projects not in Git or one-time deployments:
-
Build your project locally:
npm run build -
Upload the
out
directory:- Go to Cloudflare Pages
- Choose "Upload assets"
- Upload the contents of the
out
folder
Advanced Configuration
Custom Domain Setup
-
Add your domain:
- In your Pages project, go to "Custom domains"
- Click "Set up a custom domain"
- Enter your domain name
-
Update DNS:
- Add a CNAME record pointing to your
.pages.dev
domain - Or transfer your domain to Cloudflare for automatic configuration
- Add a CNAME record pointing to your
Security Headers
Create a _headers
file in your public
directory:
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Redirects and Rewrites
Create a _redirects
file in your public
directory:
# Redirect old blog URLs
/old-blog/* /blog/:splat 301
# SPA fallback for client-side routing
/* /index.html 200
Performance Optimization
1. Image Optimization
// Use WebP format for better compressionimport Image from 'next/image'export default function OptimizedImage() {return (<picture><source srcSet="/image.webp" type="image/webp" /><Imagesrc="/image.jpg"alt="Fallback"width={500}height={300}/></picture>)}
2. Asset Optimization
// next.config.jsconst nextConfig = {output: 'export',images: { unoptimized: true },compress: true,poweredByHeader: false,generateEtags: false,}
3. Bundle Analysis
Add bundle analyzer to understand your build:
npm install --save-dev @next/bundle-analyzer
// next.config.jsconst withBundleAnalyzer = require('@next/bundle-analyzer')({enabled: process.env.ANALYZE === 'true',})module.exports = withBundleAnalyzer(nextConfig)
Troubleshooting Common Issues
Build Failures
Issue: Build fails with export errors
Error: Image Optimization using the default loader is not compatible with export.
Solution: Enable unoptimized
images:
// next.config.jsmodule.exports = {images: {unoptimized: true}}
404 Errors
Issue: Routes return 404 in production
Solution: Ensure you have trailingSlash: true
and proper static generation:
// For dynamic routes, ensure generateStaticParams is implementedexport async function generateStaticParams() {// Return all possible param combinations}
Environment Variables
Issue: Environment variables not working
Solution: Use NEXT_PUBLIC_
prefix for client-side variables:
# In Cloudflare Pages settingsNEXT_PUBLIC_API_URL=https://api.example.com
Monitoring and Analytics
1. Cloudflare Analytics
Enable Cloudflare Analytics for:
- Page views and unique visitors
- Performance metrics
- Geographic distribution
- Bot traffic analysis
2. Real User Monitoring (RUM)
Add performance monitoring:
// lib/analytics.jsexport function initAnalytics() {if (typeof window !== 'undefined' && process.env.NODE_ENV === 'production') {// Initialize your analytics service}}
Continuous Deployment Workflow
Set up automated deployments:
# .github/workflows/deploy.ymlname: Deploy to Cloudflare Pageson:push:branches: [ main ]pull_request:branches: [ main ]jobs:deploy:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with:node-version: '18'cache: 'npm'- run: npm ci- run: npm run build- run: npm run test- name: Deploy to Cloudflare Pagesuses: cloudflare/pages-action@v1with:apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}projectName: your-project-namedirectory: out
Conclusion
Cloudflare Pages provides an excellent platform for hosting Next.js static sites with minimal configuration and maximum performance. The combination of global CDN, automatic deployments, and generous free tier makes it an ideal choice for most static sites.
Key takeaways:
- Configure Next.js for static export
- Use Git integration for automated deployments
- Implement proper redirects and security headers
- Monitor performance and optimize accordingly
Ready to deploy your Next.js app? Start with the Git integration method for the smoothest experience, and don't forget to set up a custom domain for a professional touch.
Need help with your deployment? Join our community or reach out for personalized assistance.