惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Commits to openclaw:main
Recent Commits to openclaw:main
U
Unit 42
WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
Microsoft Security Blog
Microsoft Security Blog
T
The Blog of Author Tim Ferriss
博客园 - Franky
云风的 BLOG
云风的 BLOG
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Palo Alto Networks Blog
NISL@THU
NISL@THU
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Vercel News
Vercel News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
C
Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy
小众软件
小众软件
T
Threat Research - Cisco Blogs
Project Zero
Project Zero
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Register - Security
The Register - Security
The Hacker News
The Hacker News
F
Fortinet All Blogs
Security Latest
Security Latest
Cisco Talos Blog
Cisco Talos Blog
The GitHub Blog
The GitHub Blog
Stack Overflow Blog
Stack Overflow Blog
T
The Exploit Database - CXSecurity.com
量子位
Blog — PlanetScale
Blog — PlanetScale
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
G
GRAHAM CLULEY
D
DataBreaches.Net
P
Privacy International News Feed
Y
Y Combinator Blog
Simon Willison's Weblog
Simon Willison's Weblog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
InfoQ
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
P
Proofpoint News Feed

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

Learn Command Line Interface (CLI) Development with Dart: From Zero to a Fully Published Developer Tool How to Bypass Cloud SMTP Restrictions Using Brevo and HTTP APIs How to Build a Live Options Database in Python – A Complete Guide How to Migrate to S3 Native State Locking in Terraform How to Use SCons to Build Software Projects [Full Handbook] How to Run Open Source LLMs Locally and in the Cloud QuRT: The Real-Time OS Inside Your Phone's Processor [Full Handbook] The Real Infrastructure Behind Remote Work (It’s Not Just Wi-Fi) The Lithography Handbook: Machines, Markets, and the Next Wave of Semiconductor Startups ITCM vs DTCM vs DDR: Embedded Memory Types Explained [Full Handbook] AI Paper Review: Improving Language Understanding by Generative Pre-Training (GPT-1) How to Build a Market Research Copilot with MCP and Python [Full Handbook] How to Build a Scoped Note-Taking API with Django Rest Framework and SimpleJWT The Complete SOC 2 Type II Implementation Handbook for Engineers: A Month-by-Month Roadmap with Real Commands Mastering the JavaScript Event Loop Data Science Insights: Why the Mean Lies When Handling Messy Retail Data How to Build High-Ranking SEO Landing Page How to Query Data in DynamoDB Using .Net How to Unblock Your AI PR Review Bottleneck: A Tech Lead’s Guide to Building a Codebase-Aware Reviewer How to Navigate Microservices as a Frontend Engineer How to Compress PDF Files in the Browser Using JavaScript (Step-by-Step) Stanford's youngest instructor talks InfoSec, AI, and catching cheaters - Rachel Fernandez interview [Podcast #217] Product Experimentation with Propensity Scores: Causal Inference for LLM-Based Features in Python How to Build a Multi-Agent AI System with LangGraph, MCP, and A2A [Full Book] How to Land Your First Cloud or DevOps Role: What Hiring Managers Actually Look For How to Deploy a Serverless Spam Classifier Using Scikit-Learn, AWS Lambda, & API Gateway How to Dockerize a Go Application – Full Step-by-Step Walkthrough Learn Hardware, Cloud, DevOps, Networking, Security, Databases, DNS, Git, and Linux Inside TreeHacks 2026, Stanford’s Elite Student Hakc Inside Stanford’s Elite Student Hackathon [Full Documentary] How to Measure Your AI Citation Rate Across ChatGPT, Perplexity, and Claude How to Build a Multi-Tenant SaaS Platform with Next.js, Express, and Prisma How I Completed 15 freeCodeCamp Certifications in 4 Months: A Structured Learning Journey How to Build an Agentic Terminal Workflow with GitHub Copilot CLI and MCP Servers How AI Changed the Economics of Writing Clean Code How to Apply STRIDE Threat Modeling and SonarQube Analysis for Secure Software Development How to Set Up OpenID Connect (OIDC) in GitHub Actions for AWS How to Split PDF Files in the Browser Using JavaScript (Step-by-Step) How to Build Your Own Language-Specific LLM [Full Handbook] How to Build a Self-Learning RAG System with Knowledge Reflection How to Trace Multi-Agent AI Swarms with Jaeger v2 How I Tested Malaysia's Open Data Portals with Plain English How I Built a Production-Ready CI/CD Pipeline for a Monorepo-Based Microservices System with Jenkins, Docker Compose, and Traefik The Hidden Tax of Infrastructure: Why Your Team Shouldn’t Be Running It Anymore From Metrics to Meaning: How PaaS Helps Developers Understand Production From Symptoms to Root Cause: How to Use the 5 Whys Technique Product Experimentation for AI Rollouts: Why A/B Testing Breaks and How Difference-in-Differences in Python Fixes It How to Create a GPU-Optimized Machine Image with HashiCorp Packer on GCP 3D Web Development with Blender and Three.js How to Fix a Failing GitHub PR: Debugging CI, Lint Errors, and Build Errors Step by Step How to Merge PDF Files in the Browser Using JavaScript (Step-by-Step) How to Handle Stripe Webhooks Reliably with Background Jobs How to Build an Automatic Knowledge Graph for Your Blog with PHP and JSON-LD Understanding Proxies and Reverse Proxies: Your Gateway to Secure Networking The Evolution of Nvidia Blackwell GPU Memory Architecture How to Use PostgreSQL as a Cache, Queue, and Search Engine The New Definition of Software Engineering in the Age of AI Reclaim Your Time – Master Automation with Zapier How to Create Dynamic Emails in Go with React Email Why Many Beginner Self-Taught Developers Struggle (And What to Do About It) How to Build a Headless WordPress Frontend with Astro SSR on Cloudflare Pages How to Make Your GitHub Profile Stand Out How to Use Context Hub (chub) to Build a Companion Relevance Engine Why Chrome OS Is the Operating System the AI Era Was Built For How to Build Microservices-Based REST APIs for Healthcare Portals How to friction-max your learning with software engineer Jessica Rose [Podcast #216] Shadow AI Explained: Why Employees Are Using AI Behind Your Back Traditional Scraping vs AI Scraping: A Practical Guide for Developers and Data Teams How Database Indexes Work – A Practical Guide with PostgreSQL Examples How to Streamline Search in Web Applications with Elasticsearch How to Build an Open Source Data Lake for Batch Ingestion OpenAI Codex Essentials – AI Assisted Agentic Development Course Learn Software System Design How to Generate PDF Files in the Browser Using JavaScript (With a Real Invoice Example) How to Get Started with Terraform Service-to-Service Communication: When to Use REST, gRPC, and Event-Driven Messaging A Developer’s Guide to Lazy Loading in React and Next.js The Data Quality Handbook: Data Errors, the Developer's Role, and Validation Layers Explained. United States Residential Proxy: Why Local IP Accuracy Matters for SERP, Ads, and Pricing How to Build a Fashion App That Helps You Organize Your Wardrobe How to Build an Admin Dashboard Sidebar with shadcn/ui and Base UI The AI Governance Handbook: How to Build Responsible AI Systems That Actually Ship How to Build a Local DevOps HomeLab with Docker, Kubernetes, and Ansible How to Use Mixins in Flutter [Full Handbook] How to Prep for Technical Interviews – A Guide for Web Developers GPT-5.4 vs GLM-5: Is Open Source Finally Matching Proprietary AI? Data Visualization Tools for Svelte Developers How to Keep Human Experts Visible in Your AI-Assisted Codebase Efficient Data Processing in Python: Batch vs Streaming Pipelines Explained How to Build and Deploy Multi-Architecture Docker Apps on Google Cloud Using ARM Nodes (Without QEMU) How to Build a Secure AI PR Reviewer with Claude, GitHub Actions, and JavaScript How to Build a Positioning-Based Crude Oil Strategy in Python [Full Handbook] How to learn programming and CS in the AI hype era – interview with dev and prof Mark Mahoney [Podcast #215] CUDA Programming for NVIDIA H100s How to Build Reliable AI Systems. How to Build an Online Marketplace with Next.js, Express, and Stripe Connect How to Build a Cost-Efficient AI Agent with Tiered Model Routing The WebCodecs Handbook: Native Video Processing in the Browser The Bluetooth LE Audio Handbook: From "Why Does My Call Sound Like a Tin Can?" to AOSP Implementation How to Set Up OpenClaw and Design an A2A Plugin Bridge
How to Deploy a Full-Stack Next.js App on Cloudflare Workers with GitHub Actions CI/CD
Md Tarikul I · 2026-04-29 · via freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
How to Deploy a Full-Stack Next.js App on Cloudflare Workers with GitHub Actions CI/CD

I typically build my projects using Next.js 14 (App Router) and Supabase for authentication along with Postgres. The default deployment choice for a Next.js app is usually Vercel, and for good reason: it provides an excellent developer experience.

But after running the same project on both platforms for about a week, I started exploring Cloudflare Workers as an alternative. I noticed improvements in latency (lower TTFB) and found the free tier to be more flexible for my use case.

Deploying Next.js apps on Cloudflare used to be challenging. Earlier solutions like Cloudflare Pages had limitations with full Next.js features, and tools like next-on-pages often lagged behind the latest releases.

That changed with the introduction of @opennextjs/cloudflare. It allows you to compile a standard Next.js application into a Cloudflare Worker, supporting features like SSR, ISR, middleware, and the Image component – all without requiring major code changes.

In this guide, I’ll walk you through the exact steps I used to deploy my full-stack Next.js + Supabase application to Cloudflare Workers.

This article is the runbook I wish I had when I started.

Table of Contents

Why Choose Cloudflare Workers Over Vercel?

When deploying a Next.js application, Vercel is often the default choice. It offers a smooth developer experience and tight integration with Next.js.

But Cloudflare Workers provides a compelling alternative, especially when you care about global performance and cost efficiency.

Here’s a high-level comparison (at the time of writing):

Concern Vercel (Hobby) Cloudflare Workers (Free Tier)
Requests Fair usage limits Millions of requests per day
Cold starts ~100–300 ms (region-based) Near-zero (V8 isolates)
Edge locations Limited regions for SSR 300+ global edge locations
Bandwidth ~100 GB/month (soft cap) Generous / no strict cap on free tier
Custom domains Supported Supported
Image optimization Counts toward usage Available via IMAGES binding
Pricing beyond free Starts at ~$20/month Low-cost, usage-based pricing

Key Takeaways

  • Lower latency globally: Cloudflare runs your app across hundreds of edge locations, reducing response time for users worldwide.

  • Minimal cold starts: Thanks to V8 isolates, functions start almost instantly.

  • Cost efficiency: The free tier is generous enough for portfolios, blogs, and many small-to-medium apps.

Trade-offs to Consider

Cloudflare Workers use a V8 isolate runtime, not a full Node.js environment. That means:

  • Some Node.js APIs like fs or child_process aren't available

  • Native binaries or certain libraries may not work

That said, for most modern stacks – like Next.js + Supabase + Stripe + Resend – this limitation is rarely an issue.

In short, choose Vercel if you want the simplest, plug-and-play Next.js deployment. Choose Cloudflare Workers if you want better edge performance and more flexible scaling.

Prerequisites

Before getting started, make sure you have the following set up. Most of these take only a few minutes:

  • Node.js 18+ and pnpm 9+ (you can also use npm or yarn, but this guide uses pnpm.)

  • A Cloudflare account 👉 https://dash.cloudflare.com/sign-up

  • A Supabase account (if your app uses a database) 👉 https://supabase.com

  • A GitHub repository for your project (required later for CI/CD setup)

  • A domain name (optional) – You’ll get a free *.workers.dev URL by default.

Install Wrangler (Cloudflare CLI)

We’ll use Wrangler to build and deploy the application:

pnpm add -D wrangler

The Stack

Here’s the tech stack used in this project:

  • Next.js (v14.2.x): Using the App Router with Edge runtime for both public and dashboard routes

  • Supabase: Handles authentication, Postgres database, and Row-Level Security (RLS)

  • Tailwind CSS + UI utilities: For styling, along with lightweight animation using Framer Motion

  • Cloudflare Workers: Deployment powered by @opennextjs/cloudflare and wrangler

  • GitHub Actions: Used to automate CI/CD and deployments

Note: If you're using Next.js 15 or later, you can remove the
--dangerouslyUseUnsupportedNextVersion flag from the build script, as it's only required for certain Next.js 14 setups.

Step 1 — Install the Cloudflare Adapter

From inside your existing Next.js project, install the OpenNext adapter along with Wrangler (Cloudflare’s CLI tool):

pnpm add @opennextjs/cloudflare
pnpm add -D wrangler

Then add the deploy scripts to package.json:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",

    "cloudflare-build": "opennextjs-cloudflare build --dangerouslyUseUnsupportedNextVersion",
    "preview":          "pnpm cloudflare-build && opennextjs-cloudflare preview",
    "deploy":           "pnpm cloudflare-build && wrangler deploy",
    "upload":           "pnpm cloudflare-build && opennextjs-cloudflare upload",
    "cf-typegen":       "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
  }
}

What each script does:

Script What it does
pnpm cloudflare-build Compiles your Next app into .open-next/ (the Worker bundle). No upload.
pnpm preview Builds and runs the Worker locally with wrangler dev. Closest thing to prod.
pnpm deploy Builds and uploads to Cloudflare. This ships to production.
pnpm upload Builds and uploads a new version without promoting it (for staged rollouts).
pnpm cf-typegen Regenerates cloudflare-env.d.ts types after editing wrangler.jsonc.

Heads up: the Pages-based @cloudflare/next-on-pages is a different tool. We are not using Pages — we're deploying as a real Worker. Don't mix the two.

Step 2 — Wire OpenNext into next dev

So that pnpm dev can read your Cloudflare bindings (env vars, R2, KV, D1, …) the same way production will, edit next.config.mjs:

/** @type {import('next').NextConfig} */
const nextConfig = {};

if (process.env.NODE_ENV !== "production") {
  const { initOpenNextCloudflareForDev } = await import(
    "@opennextjs/cloudflare"
  );
  initOpenNextCloudflareForDev();
}

export default nextConfig;

We only call it in development so next build stays fast and CI doesn't spin up a Miniflare instance for nothing.

Step 3 — Local Environment Setup with .dev.vars

When working with Cloudflare Workers locally, Wrangler uses a file called .dev.vars to store environment variables (instead of .env.local used by Next.js).

A simple and reliable approach is to keep an example file in your repo and ignore the real one.

Example: .dev.vars.example (committed)

NEXT_PUBLIC_SUPABASE_URL="https://YOUR-PROJECT-ref.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY="YOUR-ANON-KEY"
NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL="admin@example.com"

Set Up Your Local Environment

Run the following commands:

cp .dev.vars.example .dev.vars
cp .dev.vars .env.local
  • .dev.vars is used by Wrangler (wrangler dev)

  • .env.local is used by Next.js (next dev)

Why Use Both Files?

  • next dev reads from .env.local

  • wrangler dev (used in pnpm preview) reads from .dev.vars

Keeping both files in sync ensures your app behaves consistently in development and when running in the Cloudflare runtime.

Update .gitignore

Make sure these files are ignored:

.dev.vars
.env*.local
.open-next
.wrangler

Step 4 — Deploy Your App from Your Local Machine

Once pnpm preview is working correctly, you're ready to deploy your application:

pnpm deploy

Under the hood that runs:

pnpm cloudflare-build && wrangler deploy

The first time, Wrangler will:

  1. Compile your app to .open-next/worker.js.

  2. Upload the script + assets to Cloudflare.

  3. Print your live URL, e.g. https://porfolio.<your-account>.workers.dev.

Open it in a browser. Congratulations — you're on Cloudflare's edge in 330+ cities. The page should be served in <100 ms TTFB from anywhere.

Here's the live version of my own portfolio deployed this way

Step 5 — Push Your Secrets to the Worker

Local .dev.vars is not uploaded by wrangler deploy. You have to push secrets explicitly:

wrangler secret put NEXT_PUBLIC_SUPABASE_URL
wrangler secret put NEXT_PUBLIC_SUPABASE_ANON_KEY
wrangler secret put NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL

Each command prompts you for the value and stores it encrypted on Cloudflare. Or do it visually:

Cloudflare Dashboard → Workers & Pages → your worker → SettingsVariables and SecretsAdd.

Important: NEXT_PUBLIC_* vars are inlined into the client bundle at build time, so they also need to be available when pnpm cloudflare-build runs (locally, that's your .env.local; in CI, see Step 10).

Step 6 — Set Up Continuous Deployment with GitHub Actions

Once your local deployment is working, the next step is automating deployments so every push to the main branch updates production automatically.

With this workflow:

  • Pull requests will run validation checks

  • Production deploys only happen after successful builds

  • Broken code never reaches your live site

Create the following file inside your project:

.github/workflows/deploy.yml

name: CI / Deploy to Cloudflare Workers

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: cloudflare-deploy-${{ github.ref }}
  cancel-in-progress: true

jobs:
  verify:
    name: Lint and Build
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 10

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm build
        env:
          NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
          NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
          NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL }}

  deploy:
    name: Deploy to Cloudflare Workers
    needs: verify
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with:
          version: 10

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile

      - name: Build and Deploy
        run: pnpm run deploy
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
          NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
          NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL }}

Required GitHub repo secrets

Go to GitHub repo → Settings → Secrets and variables → Actions → New repository secret and add:

Secret Where to get it
CLOUDFLARE_API_TOKEN https://dash.cloudflare.com/profile/api-tokens → "Edit Cloudflare Workers" template
CLOUDFLARE_ACCOUNT_ID Cloudflare dashboard → right sidebar, "Account ID"
CLOUDFLARE_ACCOUNT_SUBDOMAIN Your *.workers.dev subdomain (used only for the deployment URL link)
NEXT_PUBLIC_SUPABASE_URL Supabase project settings
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase project settings
NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL Email pre-filled on /dashboard/login

That's it. Push it to main and it'll go live in about 90 seconds. PRs run lint and build only, so broken code never reaches production.

Step 7 — Updating the Project (the Daily Workflow)

After the initial setup, the loop is boringly simple — which is the whole point. Here's what I actually do day-to-day:

Code Change

git checkout -b feat/new-section
# ...edit files...
pnpm dev                # iterate locally
pnpm preview            # final smoke test on the Worker runtime
git commit -am "feat: add new section"
git push origin feat/new-section

Open a PR and the verify that the job runs. Then review, merge, and the deploy it. The job ships to Cloudflare automatically.

Updating env Vars / Secrets

# Local
nano .dev.vars

# Production
wrangler secret put NEXT_PUBLIC_SUPABASE_URL
# ...etc.

Final Thoughts

When I started this migration, I was nervous about leaving Vercel — the Next.js DX there is genuinely excellent. But the moment you push beyond a hobby site, Cloudflare's economics and edge performance are not close.

With @opennextjs/cloudflare, the developer experience has also caught up: my pnpm dev loop is identical, my pnpm preview mimics production, and git push deploys globally in ~90 seconds.

If you've been holding off because the old Cloudflare Pages + Next.js story was rough, that era is over. Try this runbook on a side project this weekend and see for yourself.

If you found this useful, the full repo is here — feel free to clone it as a starter.

Happy shipping.

Tarikul



Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. Get started