Deploy Next.js Supabase to Cloudflare
Deploy your MakerKit Next.js Supabase application to Cloudflare Pages using the Edge runtime. Covers configuration changes, OpenNext setup, and deployment.
Deploy your MakerKit Next.js 16 application to Cloudflare Pages using OpenNext for Edge runtime deployment. Cloudflare offers zero cold starts, global distribution, and cost-effective pricing for high-traffic applications.
Prerequisites
Before deploying to Cloudflare:
- Cloudflare Workers Paid Plan: Required due to bundle size limits on the free tier (starts at $5/month)
- Set up Supabase project
- Generate environment variables
Edge Runtime Considerations
Cloudflare uses the Edge runtime, which differs from Node.js. Before proceeding, understand these limitations:
What Works Differently
| Feature | Node.js | Edge Runtime | Solution |
|---|---|---|---|
| File system | Full access | No access | Use remote CMS |
| Nodemailer | Supported | Not supported | Use Resend or HTTP mailer |
| Pino logger | Supported | Not supported | Use console logger |
| Stripe SDK | Default config | Needs fetch client | Add httpClient option |
| Database latency | Low | Potentially higher | Choose region wisely |
Benefits
- Zero cold starts
- Global edge deployment (runs close to users)
- Lower costs for high-traffic applications
- Excellent caching capabilities
Step 1: Run the Cloudflare Generator
MakerKit provides a generator that scaffolds all required Cloudflare configuration:
pnpm run turbo gen cloudflareThis command:
- Creates
wrangler.jsoncconfiguration file - Creates
open-next.config.tsfor OpenNext - Creates
.dev.varsfor local development variables - Adds OpenNext and Wrangler dependencies
- Updates
next.config.mjswith OpenNext initialization - Adds deployment scripts to
package.json
Step 2: Switch to Console Logger
Pino logger uses Node.js APIs unavailable in Edge runtime. Switch to console logging:
LOGGER=consoleAdd this to both your .env file and Cloudflare environment variables.
Step 3: Update Stripe Client
The default Stripe SDK configuration uses Node.js HTTP which doesn't work in Edge runtime. You need to modify the Stripe client to use the fetch-based HTTP client instead.
Open packages/billing/stripe/src/services/stripe-sdk.ts and add the httpClient option to the Stripe constructor:
return new Stripe(stripeServerEnv.secretKey, { apiVersion: STRIPE_API_VERSION, httpClient: Stripe.createFetchHttpClient(), // ADD THIS LINE});Manual change required
This modification is not included in MakerKit by default. You must add the httpClient: Stripe.createFetchHttpClient() line yourself when deploying to Edge runtime (Cloudflare or Vercel Edge Functions).
The httpClient option tells Stripe to use the Fetch API instead of Node.js HTTP, making it compatible with Edge runtime.
Step 4: Rename proxy.ts to middleware.ts
Rename apps/web/proxy.ts to apps/web/middleware.ts.
This is required until OpenNext supports the new proxy.ts convention. See this Github issue for more details.
Step 5: Switch to HTTP-Based Mailer
Nodemailer relies on Node.js networking APIs. Use Resend instead, which uses the Fetch API:
MAILER_PROVIDER=resendRESEND_API_KEY=re_your_api_keyEMAIL_SENDER=noreply@yourdomain.comIf you need a different email provider, implement a custom mailer using the abstract class in packages/mailers. Ensure your implementation uses only Fetch API for HTTP requests.
Step 6: Switch CMS Provider
Keystatic's local mode reads from the file system, which isn't available in Edge runtime. Choose one of these alternatives:
Option A: WordPress
Set your CMS to WordPress:
CMS_CLIENT=wordpressConfigure your WordPress instance as the content source. See the WordPress CMS documentation for setup.
Option B: Keystatic GitHub Mode
Keep Keystatic but use GitHub as the storage backend instead of local files:
- Configure Keystatic for GitHub mode in your
keystatic.config.ts - Set up GitHub App or Personal Access Token
- Content is stored in your GitHub repository
See the Keystatic documentation for GitHub mode setup.
Step 7: Configure Environment Variables
For Local Development
Add variables to apps/web/.dev.vars:
NEXT_PUBLIC_SITE_URL=http://localhost:3000NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.coNEXT_PUBLIC_SUPABASE_PUBLIC_KEY=eyJ...SUPABASE_SECRET_KEY=eyJ...LOGGER=consoleMAILER_PROVIDER=resendRESEND_API_KEY=re_...# ... other variablesFor Production
You'll set these during deployment or via the Cloudflare Dashboard.
Step 8: Preview Locally
Test your application in a Cloudflare-like environment before deploying:
pnpm --filter web run previewThis builds the application with OpenNext and runs it in Wrangler's local development server. Test all critical paths:
- Authentication flows
- Billing checkout
- Email sending
- Database operations
Test thoroughly
Edge runtime differences may cause unexpected issues. Test your entire application flow before deploying to production.
Step 8: Deploy to Cloudflare
Deploy your application:
pnpm --filter web run deployThis command:
- Builds your Next.js application with OpenNext
- Uploads to Cloudflare Pages
- Deploys to the edge network
Dashboard deployment not supported
At the time of writing, Cloudflare's Dashboard doesn't support OpenNext deployments. Use the CLI command instead.
Additional Commands
Generate TypeScript Types
Generate types for Cloudflare environment bindings:
pnpm --filter web run cf-typegenThis creates cloudflare-env.d.ts with type definitions for your Cloudflare environment.
View Deployment Logs
Check your Cloudflare Dashboard under Workers & Pages for deployment logs and analytics.
Production Configuration
Custom Domain
- Go to Cloudflare Dashboard > Workers & Pages
- Select your project
- Go to Custom Domains
- Add your domain
Cloudflare automatically provisions SSL certificates.
Environment Variables in Dashboard
Add production secrets via the Cloudflare Dashboard:
- Go to Workers & Pages > Your Project > Settings
- Click Variables
- Add each secret variable
Or use Wrangler CLI:
wrangler secret put STRIPE_SECRET_KEYCaching Strategy
Cloudflare's edge caching works well with Next.js ISR. Configure cache headers in your next.config.mjs for optimal performance.
Troubleshooting
"Script size exceeds limit"
Your bundle exceeds Cloudflare's free tier limit. You need the Workers Paid plan ($5/month).
"Cannot find module 'fs'"
You're using a library that requires Node.js file system APIs. Options:
- Find an Edge-compatible alternative
- Use dynamic imports with fallbacks
- Move the functionality to an external API
"fetch is not defined"
Ensure you're using the Fetch API correctly. In Edge runtime, fetch is globally available without importing.
Stripe errors
Verify you've added httpClient: Stripe.createFetchHttpClient() to your Stripe configuration.
Email sending fails
Confirm:
MAILER_PROVIDER=resendis setRESEND_API_KEYis configured- You're not accidentally importing nodemailer
Database timeouts
Edge functions may have higher latency to your database. Consider:
- Placing your Supabase project in a region close to your edge deployment
- Using connection pooling
- Optimizing query performance
Build fails with OpenNext errors
- Ensure all dependencies are installed:
pnpm install - Clear build caches:
rm -rf .next .open-next - Check for Node.js-specific code in your pages
Performance Optimization
Regional Deployment
By default, Cloudflare deploys globally. If your users are concentrated in a region, consider:
- Deploying Supabase in the same region
- Using Cloudflare's Smart Placement feature
Cache Optimization
Leverage Cloudflare's caching:
// In your API routesexport const runtime = 'edge';export const revalidate = 3600; // Cache for 1 hourBundle Size
Keep your bundle small for faster cold starts:
- Use dynamic imports for large components
- Avoid importing entire libraries when you only need specific functions
- Check your bundle with
next build --analyze
Frequently Asked Questions
Why do I need the Workers Paid plan?
Can I use Keystatic with Cloudflare?
Why isn't nodemailer working?
How do I debug Edge runtime issues?
Next Steps
- Vercel Deployment: Alternative with full Node.js support
- Environment Variables: Complete variable reference
- CMS Configuration: Set up WordPress or Keystatic GitHub mode