Cloudflare Platform

Understanding the Cloudflare runtime model is essential before picking a framework. The platform has quirks that eliminate some frameworks and favor others. For a deeper look at the runtime, see the Platform Model concept in the Cloudflare platform topic.

Workers vs Pages

Cloudflare has two deployment targets. Pages is being phased out.

WorkersPages
StatusActive, recommendedLegacy, maintenance mode
Static assetsWorkers Static AssetsPages Functions
Server codeFull Worker entry pointLimited Functions
BindingsAll (KV, D1, R2, DO, Queues, AI)Subset
Configwrangler.jsonc or wrangler.tomlDashboard or wrangler.toml

Gotcha: New projects should target Workers, not Pages. Astro’s adapter v13 dropped Pages support entirely. Cloudflare’s framework guides now default to Workers.

The Runtime: workerd

Cloudflare Workers run on workerd, not Node.js. Key differences:

// These Node.js APIs don't exist in workerd:
// - fs, path, child_process, net, os
// - process.env (use env bindings instead)
// - __dirname, __filename
// - require() (ESM only)

// These DO work:
// - fetch, Request, Response, Headers
// - URL, URLSearchParams
// - crypto (Web Crypto API)
// - TextEncoder, TextDecoder
// - setTimeout, setInterval (limited)
// - console.log

The nodejs_compat flag enables polyfills for some Node.js APIs (Buffer, crypto, stream, etc.), but filesystem and process APIs remain unavailable.

// wrangler.jsonc
{
  "compatibility_flags": ["nodejs_compat"]
}

Bindings

Bindings are how Workers access Cloudflare services. They’re injected at runtime, not imported.

// In a Worker entry point
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // env contains your bindings
    const value = await env.MY_KV.get("key");
    const result = await env.MY_DB.prepare("SELECT * FROM users").all();
    const object = await env.MY_BUCKET.get("file.png");
    return new Response(value);
  }
};

Common binding types:

BindingConfig keyUse for
KVkv_namespacesKey-value storage
D1d1_databasesSQL database
R2r2_bucketsObject storage
Durable Objectsdurable_objectsStateful coordination (deep-dive)
QueuesqueuesAsync message processing
AIaiInference (Workers AI)
VectorizevectorizeVector search
Service BindingsservicesWorker-to-Worker calls

Accessing Bindings in Frameworks

Each framework has its own pattern for accessing bindings:

// React Router v7 - loader/action context
export async function loader({ context }: LoaderFunctionArgs) {
  const env = context.cloudflare.env;
  return await env.MY_KV.get("key");
}

// Astro - module import (v13+)
import { env } from "cloudflare:workers";
const value = await env.MY_KV.get("key");

// SvelteKit - platform object
export async function load({ platform }) {
  return await platform.env.MY_KV.get("key");
}

// Hono - context
app.get("/", async (c) => {
  const value = await c.env.MY_KV.get("key");
  return c.text(value);
});

// Next.js (OpenNext) - getRequestContext
import { getRequestContext } from "@opennextjs/cloudflare";
const { env } = getRequestContext();

The Cloudflare Vite Plugin

The @cloudflare/vite-plugin is Cloudflare’s answer to the dev/prod parity problem. Without it, vite dev runs your server code in Node.js, but production runs in workerd. Bugs only show up after deploying.

flowchart LR
    subgraph "Without CF Vite Plugin"
        A[vite dev] -->|Node.js| B[Your server code]
        C[wrangler deploy] -->|workerd| D[Your server code]
    end
flowchart LR
    subgraph "With CF Vite Plugin"
        E[vite dev] -->|workerd via Vite Environment API| F[Your server code]
        G[wrangler deploy] -->|workerd| H[Your server code]
    end

The plugin uses Vite’s Environment API to run server-side code inside a local workerd instance during development. Bindings, runtime APIs, and compatibility flags all behave identically in dev and prod.

Which Frameworks Use It

FrameworkCF Vite PluginDev runtime
React Router v7Yesworkerd
TanStack StartYesworkerd
Astro (adapter v13)Yesworkerd
Vite + React SPAYesworkerd (for assets)
SvelteKitNoNode.js
NuxtNoNode.js
Next.js (OpenNext)NoNode.js
HonoOptionalworkerd if configured

Wrangler Auto-Detection

Running npx wrangler deploy in a framework project without a config file triggers auto-detection:

  1. Detects the framework from package.json
  2. Generates appropriate wrangler.jsonc
  3. Installs required adapters
  4. Builds and deploys

Supported frameworks for auto-detection: React Router v7, Astro, SvelteKit, Nuxt, Qwik, SolidStart, and Vite + React/Vue SPAs.

Gotcha: Auto-detection doesn’t work for Next.js (needs OpenNext setup) or Hono (already a native Worker).

Resource Limits

Workers have hard limits that affect framework choice:

ResourceFreePaid
CPU time per request10ms30s (up to 5min via limits.cpu_ms)
Memory128MB128MB
Script size (compressed)3MB10MB
Subrequests per request5010,000
Environment variables64128

Gotcha: The 3MB free-tier script size limit (compressed) can be tight for frameworks with large server bundles (Nuxt, Next.js). Check your bundle size with wrangler deploy --dry-run.