Cloudflare Pages — Free Full-Stack Deployment on the Global Edge

Posted on: 4/26/2026 11:16:06 PM

Have you ever wanted to deploy a full-stack web application for absolutely free, with no server management, and have it automatically distributed across 330+ data centers worldwide? Cloudflare Pages makes that a reality. It's not just a static hosting platform — with Pages Functions, bindings to KV, D1, R2, and even Workers AI — Cloudflare Pages has become a complete full-stack serverless platform running on the edge.

330+Global data centers
$0Bandwidth cost (unlimited)
500Free builds/month
100KFunction requests/day (free)

1. What Is Cloudflare Pages?

Cloudflare Pages is a JAMstack platform that lets you deploy web applications directly onto Cloudflare's global edge network. Unlike traditional hosting that places your server in a single region, Pages distributes content to the node closest to each user — minimizing latency to near-zero.

The standout feature: Cloudflare Pages offers unlimited bandwidth on the free tier. Compared to Vercel (100GB/month) or Netlify (100GB/month), this is a massive advantage for high-traffic websites.

graph TB
    A["Developer pushes code"] --> B["Git Provider
(GitHub/GitLab)"] B --> C["Cloudflare Build Pipeline"] C --> D["Static Assets"] C --> E["Pages Functions"] D --> F["CDN Edge
330+ PoPs"] E --> G["Workers Runtime
Edge Compute"] F --> H["Global Users"] G --> H style A fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style C fill:#e94560,stroke:#fff,color:#fff style D fill:#2c3e50,stroke:#fff,color:#fff style E fill:#2c3e50,stroke:#fff,color:#fff style F fill:#4CAF50,stroke:#fff,color:#fff style G fill:#4CAF50,stroke:#fff,color:#fff style H fill:#e94560,stroke:#fff,color:#fff

Figure 1: Deployment and content distribution flow on Cloudflare Pages

2. Three Ways to Deploy to Cloudflare Pages

Connect your repository from GitHub or GitLab. Every time you push code, Cloudflare automatically builds and deploys. The main branch deploys to production, while other branches create separate preview deployments with unique URLs.

# Project structure: Vue.js + Pages Functions
my-app/
├── src/                    # Frontend source
��   ├── App.vue
│   └── main.ts
├── functions/              # Pages Functions (server-side)
│   ├── api/
│   │   ├── hello.ts       # GET /api/hello
│   │   └── users/
│   │       └── [id].ts    # GET /api/users/:id
│   └── _middleware.ts      # Global middleware
├── public/
├── package.json
└── wrangler.toml           # Cloudflare configuration

2.2. Direct Upload

Upload pre-built directories via Dashboard or Wrangler CLI. Ideal when you use a separate CI/CD pipeline (GitHub Actions, GitLab CI) and want full control over the build process.

# Upload via Wrangler CLI
npx wrangler pages deploy ./dist --project-name=my-app

# Or create a new project and deploy
npx wrangler pages project create my-app
npx wrangler pages deploy ./dist --project-name=my-app --branch=main

2.3. C3 (Create Cloudflare CLI)

The official scaffolding tool that auto-detects frameworks and configures builds:

# Create a new project with your framework of choice
npm create cloudflare@latest my-app

# Choose framework: Vue, React, Nuxt, Astro, SvelteKit, Remix...
# C3 auto-configures wrangler.toml and deploy commands

3. Pages Functions — Turning Static Sites into Full-Stack Apps

Pages Functions run on the Cloudflare Workers runtime using file-based routing similar to Next.js or Nuxt. Each file in the functions/ directory maps to an API endpoint.

Advantages over traditional serverless

Pages Functions start in milliseconds (no cold start like AWS Lambda). Code runs on V8 isolates, not containers — lighter, faster, and more resource-efficient.

3.1. File-based Routing

File pathRouteNotes
functions/api/hello.ts/api/helloStatic route
functions/api/users/[id].ts/api/users/:idDynamic param
functions/api/posts/[[path]].ts/api/posts/*Catch-all route
functions/_middleware.tsAll routesGlobal middleware

3.2. Writing API Endpoints

// functions/api/hello.ts
export const onRequestGet: PagesFunction = async (context) => {
  return Response.json({
    message: "Hello from Cloudflare Edge!",
    timestamp: new Date().toISOString(),
    colo: context.request.cf?.colo, // Nearest data center
  });
};

// functions/api/users/[id].ts
interface Env {
  DB: D1Database;  // Binding to D1
}

export const onRequestGet: PagesFunction<Env> = async (context) => {
  const userId = context.params.id;
  const user = await context.env.DB
    .prepare("SELECT * FROM users WHERE id = ?")
    .bind(userId)
    .first();

  if (!user) {
    return new Response("Not found", { status: 404 });
  }
  return Response.json(user);
};

3.3. Middleware — Authentication and Logging

// functions/_middleware.ts
export const onRequest: PagesFunction = async (context) => {
  const start = Date.now();
  const response = await context.next();
  response.headers.set("Access-Control-Allow-Origin", "*");
  response.headers.set("X-Response-Time", `${Date.now() - start}ms`);
  return response;
};

// functions/api/_middleware.ts — applies only to /api/*
export const onRequest: PagesFunction = async (context) => {
  const authHeader = context.request.headers.get("Authorization");
  if (!authHeader?.startsWith("Bearer ")) {
    return new Response("Unauthorized", { status: 401 });
  }
  context.data.user = await verifyToken(authHeader.slice(7));
  return context.next();
};

4. Bindings — Connecting the Cloudflare Ecosystem

The real power of Pages Functions lies in bindings — direct connections to Cloudflare services without making network API calls. Data flows within the same data center, with near-zero latency.

graph LR
    PF["Pages Functions"] --> KV["Workers KV
Key-Value Store"] PF --> D1["D1 Database
Serverless SQLite"] PF --> R2["R2 Storage
Object Storage"] PF --> DO["Durable Objects
Stateful Edge"] PF --> AI["Workers AI
ML Inference"] PF --> Q["Queues
Message Queue"] style PF fill:#e94560,stroke:#fff,color:#fff style KV fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style D1 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style R2 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style DO fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style AI fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style Q fill:#f8f9fa,stroke:#e94560,color:#2c3e50

Figure 2: Bindings connecting Pages Functions to the Cloudflare ecosystem

4.1. KV — Ultra-Fast Key-Value Storage

Workers KV is a distributed key-value store spanning the entire edge network. Perfect for caching, configuration, and session data with sub-10ms reads at the edge.

// wrangler.toml
[[kv_namespaces]]
binding = "CACHE"
id = "xxxx"

// functions/api/config.ts
interface Env {
  CACHE: KVNamespace;
}

export const onRequestGet: PagesFunction<Env> = async (context) => {
  let config = await context.env.CACHE.get("site-config", "json");

  if (!config) {
    config = await fetchConfigFromOrigin();
    await context.env.CACHE.put("site-config", JSON.stringify(config), {
      expirationTtl: 3600,
    });
  }

  return Response.json(config);
};

4.2. D1 — SQL Database on the Edge

D1 is a serverless SQLite database running at the edge. The free tier allows 5 million reads/day and 100K writes/day — more than enough for most personal projects and early-stage startups.

# Create database and run migrations
npx wrangler d1 create my-db
npx wrangler d1 execute my-db --file=./schema.sql

-- schema.sql
CREATE TABLE posts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  slug TEXT UNIQUE NOT NULL,
  content TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_posts_slug ON posts(slug);

4.3. R2 — Object Storage with Zero Egress Fees

R2 is S3-compatible but charges zero egress fees. Free tier: 10GB storage, 10 million reads/month. Ideal for image hosting, file uploads, and static assets.

// functions/api/upload.ts
interface Env {
  ASSETS: R2Bucket;
}

export const onRequestPost: PagesFunction<Env> = async (context) => {
  const formData = await context.request.formData();
  const file = formData.get("file") as File;

  if (!file) {
    return new Response("No file uploaded", { status: 400 });
  }

  const key = `uploads/${Date.now()}-${file.name}`;
  await context.env.ASSETS.put(key, file.stream(), {
    httpMetadata: { contentType: file.type },
  });

  return Response.json({ url: `/cdn/${key}`, size: file.size });
};

4.4. Workers AI — ML Inference at the Edge

Run AI models directly on Cloudflare infrastructure — text generation, image classification, embeddings, translation — no separate GPU servers needed.

// functions/api/summarize.ts
interface Env {
  AI: Ai;
}

export const onRequestPost: PagesFunction<Env> = async (context) => {
  const { text } = await context.request.json();

  const result = await context.env.AI.run(
    "@cf/meta/llama-3.1-8b-instruct",
    {
      messages: [
        { role: "system", content: "Summarize the following text concisely in 3 sentences." },
        { role: "user", content: text },
      ],
    }
  );

  return Response.json({ summary: result.response });
};

5. Preview Deployments and Rollbacks

Every pull request automatically receives a unique preview URL (e.g., abc123.my-app.pages.dev). Reviewers can access the preview directly to verify changes without affecting production.

Instant Rollbacks

Discovered a bug after deploying? Just one click on the Dashboard rolls back to any previous deployment. No need to revert code or rebuild — the previous version is activated instantly since every deployment is already cached on the edge.

6. Cloudflare Pages vs Vercel vs Netlify

CriteriaCloudflare PagesVercelNetlify
Bandwidth (Free)Unlimited100 GB/month100 GB/month
Builds/month (Free)5006,000300 minutes
Serverless Functions100K req/day100K req/month125K req/month
Edge RuntimeV8 Isolate (everywhere)Edge + ServerlessEdge Functions (Deno)
Integrated DatabaseD1 (SQLite), 5GB freePostgres (Neon)None
Object StorageR2 (10GB, zero egress)Blob StorageBlobs
Cold Start~0ms (V8 isolate)~250ms (Lambda)~200ms
Custom Domains (Free)100/project50/projectUnlimited
DDoS ProtectionBuilt-in, free, unlimitedBasicBasic

When to choose Cloudflare Pages?

Choose Pages when you need unlimited bandwidth, low global latency, and zero cold start. Choose Vercel for Next.js with complex ISR/SSR. Choose Netlify for built-in CMS integration and form handling.

7. Deploying Vue.js to Cloudflare Pages — Practical Guide

End-to-end workflow for deploying a Vue.js app with API backend on Pages Functions:

# Step 1: Create Vue + Cloudflare project
npm create cloudflare@latest my-vue-app -- --framework=vue

# Step 2: Add Pages Functions
mkdir -p functions/api

# Step 3: Configure wrangler.toml
name = "my-vue-app"
compatibility_date = "2026-04-01"
pages_build_output_dir = "./dist"

[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "your-database-id"

[[kv_namespaces]]
binding = "CACHE"
id = "your-kv-id"

# Step 4: Local development
npx wrangler pages dev -- npx vite

# Step 5: Deploy
npx wrangler pages deploy ./dist

Configure proxy for local development in vite.config.ts:

// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8788',
        changeOrigin: true,
      },
    },
  },
});

8. Free Tier Limits in Detail

ServiceFree TierNotes
Pages HostingUnlimited bandwidth, 500 builds/monthNo credit card required
Pages Functions100,000 requests/dayRuns on Workers runtime
Workers KV100K reads/day, 1K writes/day, 1GBEventually consistent
D1 Database5M reads/day, 100K writes/day, 5GBServerless SQLite
R2 Storage10GB, 10M reads/month, 1M writes/monthS3-compatible, zero egress
Workers AI10,000 neurons/dayMany free models available
Queues1M operations/monthMessage queue

Important Limits to Note

Max file size per asset: 25 MB. Max files per site: 20,000 (free) or 100,000 (paid). Build timeout: 20 minutes. Workers CPU time limited to 10ms (free) or 30 seconds (paid) per request.

9. Performance Optimization on Cloudflare Pages

9.1. Cache Control for Static Assets

// functions/_middleware.ts
export const onRequest: PagesFunction = async (context) => {
  const response = await context.next();
  const url = new URL(context.request.url);

  // Immutable cache for content-hashed assets
  if (url.pathname.match(/\/assets\/.*\.[a-f0-9]{8}\./)) {
    response.headers.set(
      "Cache-Control",
      "public, max-age=31536000, immutable"
    );
  }

  return response;
};

9.2. Smart Placement

By default, Functions run at the edge closest to the user. If a function needs to query a database in a specific region, Smart Placement automatically moves the function closer to the data source to reduce round-trips.

# wrangler.toml
[placement]
mode = "smart"

9.3. Automatic CDN Integration

When you add a custom domain, your website automatically receives full Cloudflare features:

  • HTTP/3 + QUIC — the fastest transport protocol available
  • Brotli compression — 20-30% smaller than Gzip
  • Early Hints (103) — browser starts loading resources before the main response arrives
  • DDoS Protection — free, unlimited, automatic
  • SSL/TLS — free HTTPS for every custom domain
  • Web Analytics — privacy-first analytics without client-side scripts

10. CI/CD Workflow for Teams

sequenceDiagram
    participant Dev as Developer
    participant GH as GitHub
    participant CF as Cloudflare Pages
    participant Edge as Edge Network

    Dev->>GH: Push feature branch
    GH->>CF: Webhook trigger
    CF->>CF: Build & test
    CF->>Edge: Deploy preview
    CF-->>GH: Comment preview URL

    Note over Dev,GH: Code review on preview URL

    Dev->>GH: Merge to main
    GH->>CF: Webhook trigger
    CF->>CF: Build production
    CF->>Edge: Deploy globally
    CF-->>Dev: Deploy notification

Figure 3: Automated CI/CD workflow with Git integration

11. When NOT to Use Cloudflare Pages

Pages works great for most web apps, but there are cases where alternatives may be better:

  • Long-running processes — Workers CPU time is limited to 30 seconds (paid). Heavy processing should use Queues + Workers or switch to containers (Fly.io, Railway).
  • Complex relational databases — D1 is SQLite and doesn't support complex stored procedures or multi-master replication. For full PostgreSQL/MySQL, combine Pages with an external database (Neon, PlanetScale).
  • Full Next.js App Router — Some ISR on-demand features aren't fully supported on Pages yet. Vercel remains the best choice for Next.js.
  • Persistent WebSockets — Pages Functions are stateless. WebSockets require Durable Objects combined with Workers.

Conclusion

Cloudflare Pages has evolved far beyond its "static site hosting" origins. With Pages Functions, bindings to D1/KV/R2/AI, and a network spanning 330+ data centers — it's the most powerful free full-stack serverless platform available today. Unlimited bandwidth, zero cold starts, and deep integration with Cloudflare's security ecosystem (WAF, DDoS, Bot Management) make it a top choice for individual developers, startups, and even large-scale production deployments.

If you're looking for a place to deploy your Vue.js, Nuxt, Astro, or any framework application without worrying about bandwidth costs, Cloudflare Pages deserves to be your first choice.

References