Workers Frameworks Integration
Build full-stack applications on Cloudflare Workers using modern frameworks.
Quick Start: Choose Your Framework
| Framework |
Best For |
SSR |
Static |
Workers Native |
| 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
| Error |
Framework |
Cause |
Solution |
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:
| Reference |
Load When |
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