Build full-stack applications on Cloudflare Workers using modern frameworks.
Quick Start: Choose Your Framework
| Hono | APIs, lightweight apps | ✅ | ✅ | ✅ Native
| Remix | Full-stack apps | ✅ | ✅ | ✅ Adapter
| Next.js | React apps | ✅ | ✅ | ⚠️ OpenNext
| Astro | Content sites | ✅ | ✅ | ✅ Adapter
| SvelteKit | Svelte apps | ✅ | ✅ | ✅ Adapter
| Qwik | Resumable apps | ✅ | ✅ | ✅ Adapter
| Nuxt | Vue apps | ✅ | ✅ | ✅ Nitro
Framework Decision Tree
Need an API only?
└─ Yes → Hono (fastest, smallest)
└─ No → Building a full app?
└─ React → Next.js (OpenNext) or Remix
└─ Vue → Nuxt
└─ Svelte → SvelteKit
└─ Content-heavy → Astro
└─ Max performance → Qwik
Top 10 Framework Errors
| No matching export "default"
| All
| Wrong export format
| Use export default app not module.exports
| Worker exceeded CPU limit
| Next.js
| Heavy SSR
| Use ISR, reduce bundle size
| Cannot read properties of undefined (reading 'env')
| Remix
| Missing context
| Pass context to loader/action
| globalThis is not defined
| All
| Node.js globals
| Use nodejs_compat flag
| Dynamic require not supported
| All
| CJS in ESM
| Convert to ESM imports
| Response body is locked
| All
| Body already read
| Clone response before reading
| Bindings not available
| All
| Missing wrangler config
| Add bindings to wrangler.jsonc
| 404 on static assets
| All
| Wrong assets config
| Configure assets in wrangler.jsonc
| Hydration mismatch
| React/Vue
| Server/client differ
| Ensure consistent rendering
| Maximum call stack exceeded
| All
| Circular imports
| Refactor module structure
Hono Quick Start (Recommended)
// src/index.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
interface Env {
DB: D1Database;
KV: KVNamespace;
}
const app = new Hono<{ Bindings: Env }>();
// Middleware
app.use('*', logger());
app.use('/api/*', cors());
// Routes
app.get('/', (c) => c.text('Hello Workers!'));
app.get('/api/users', async (c) => {
const { results } = await c.env.DB.prepare('SELECT * FROM users').all();
return c.json(results);
});
app.post('/api/users', async (c) => {
const { name, email } = await c.req.json();
await c.env.DB.prepare('INSERT INTO users (name, email) VALUES (?, ?)')
.bind(name, email)
.run();
return c.json({ success: true }, 201);
});
export default app;
// wrangler.jsonc
{
"name": "my-app",
"main": "src/index.ts",
"compatibility_date": "2024-12-01",
"compatibility_flags": ["nodejs_compat"],
"d1_databases": [
{ "binding": "DB", "database_name": "my-db", "database_id": "xxx" }
]
}
Static Assets Configuration
// wrangler.jsonc - Serving static files
{
"name": "my-app",
"main": "src/index.ts",
"assets": {
"directory": "./public",
"binding": "ASSETS"
}
}
// Serve static with fallback to app
import { Hono } from 'hono';
const app = new Hono<{ Bindings: { ASSETS: Fetcher } }>();
// API routes
app.get('/api/*', apiHandler);
// Static assets fallback
app.get('*', async (c) => {
return c.env.ASSETS.fetch(c.req.raw);
});
export default app;
When to Load References
Load the specific framework reference when user:
| references/hono.md
| Building APIs, microservices, or lightweight apps
| references/remix.md
| Full-stack React with loaders/actions
| references/nextjs.md
| Next.js App Router on Workers via OpenNext
| references/astro.md
| Content sites, blogs, docs, marketing pages
| references/sveltekit.md
| Svelte applications on Workers
| references/qwik.md
| Resumable apps, instant loading
| references/nuxt.md
| Vue 3 applications with Nitro
Common Patterns Across Frameworks
Environment Bindings Access
// Hono
app.get('/', (c) => c.env.DB.prepare('...'));
// Remix
export async function loader({ context }) {
return context.cloudflare.env.DB.prepare('...');
}
// Astro
const db = Astro.locals.runtime.env.DB;
// SvelteKit
export async function load({ platform }) {
return platform.env.DB.prepare('...');
}
// Nuxt
const { cloudflare } = useRuntimeConfig();
// Or via nitro: event.context.cloudflare.env.DB
Error Handling Pattern
// Universal error boundary pattern
app.onError((err, c) => {
console.error(`[${c.req.path}] ${err.message}`);
if (err instanceof HTTPException) {
return err.getResponse();
}
return c.json(
{ error: 'Internal Server Error' },
500
);
});
Performance Tips
-
Bundle Size: Keep under 1MB compressed
-
Cold Starts: Minimize top-level code
-
Streaming: Use streaming SSR when available
-
Caching: Leverage Cache API and CDN
-
Code Splitting: Dynamic imports for routes
See Also
-
workers-performance- Optimization techniques -
workers-runtime-apis- Workers APIs reference -
cloudflare-worker-base- Basic Workers setup