Skip to content

Cloudwerk

Pre-Alpha

Build for the Edge.
Ship Without the Complexity.

Cloudwerk is a full-stack framework for Cloudflare Workers. Start simple. Scale infinitely. One codebase. One deploy command.

Zero cold starts • Global edge deployment • Built on Cloudflare
Terminal
█
Scroll to explore

The Developer Journey

Follow a startup's evolution from a simple landing page to a full-stack edge application—adding features one chapter at a time.

Scroll to explore
Chapter 1

The Landing Page

You have an idea. Let's validate it.

Every great product starts with a landing page. With Cloudwerk, you're production-ready in minutes—not hours. Just create a route, connect your database, and deploy.

Routes D1 Database
Cloudwerk Project
export default function Home() {
return (
<main>
<h1>Coming Soon</h1>
<form action="/api/waitlist" method="POST">
<input name="email" type="email" required />
<button type="submit">Join Waitlist</button>
</form>
</main>
);
}
import { db } from '@cloudwerk/bindings'
export async function POST(request: Request) {
const { email } = await request.json()
await db.prepare(`
INSERT INTO waitlist (email, created_at)
VALUES (?, datetime('now'))
`).bind(email).run()
return Response.json({ success: true })
}
Deploy
█
Chapter 2

Confirmation Emails

People are signing up! Let's confirm their interest.

Create a reusable email service that lives alongside your app. Services start local—running in the same worker—so there's zero latency and zero configuration.

+ Services (Local)
Cloudwerk Project
import { defineService } from '@cloudwerk/service'
interface EmailService {
sendWelcome(params: { to: string; position: number }): Promise<void>
}
export default defineService<EmailService>({
name: 'email',
methods: {
async sendWelcome({ to, position }) {
await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.RESEND_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
to,
subject: `You're #${position} on the waitlist!`,
html: `<h1>You're in!</h1><p>You're #${position} in line.</p>`,
}),
})
},
},
})
import { db, services } from '@cloudwerk/bindings'
export async function POST(request: Request) {
const { email } = await request.json()
const result = await db.prepare(`
INSERT INTO waitlist (email) VALUES (?) RETURNING id
`).bind(email).first()
await services.email.sendWelcome({
to: email,
position: result.id
})
return Response.json({ success: true, position: result.id })
}
Chapter 3

Don't Block the Response

Emails are slowing down signups. Let's queue them.

Sending emails inline adds latency. Move them to a queue and respond instantly. Cloudwerk queues are just files—define a handler and start sending.

+ Queues
Cloudwerk Project
import { defineQueue } from '@cloudwerk/queue'
import { services } from '@cloudwerk/bindings'
interface WelcomeEmail {
to: string
position: number
}
export default defineQueue<WelcomeEmail>({
name: 'emails',
async process(message) {
await services.email.sendWelcome(message.body)
},
})
import { db, queues } from '@cloudwerk/bindings'
export async function POST(request: Request) {
const { email } = await request.json()
const result = await db.prepare(`
INSERT INTO waitlist (email) VALUES (?) RETURNING id
`).bind(email).first()
// Queue email — respond instantly!
await queues.emails.send({
to: email,
position: result.id
})
return Response.json({ success: true, position: result.id })
}
BEFOREUser waits 800ms (DB + Email API)
AFTERUser waits 50ms (DB + Queue)
Chapter 4

Viral Referrals

Let's incentivize sharing with a real-time leaderboard.

Durable Objects give you strongly consistent, real-time state at the edge. Perfect for counters, leaderboards, and collaboration. Each user gets their own referral code, and the leaderboard updates live via WebSocket.

+ Durable Objects Real-time WebSocket
Cloudwerk Project
import { defineDurableObject } from '@cloudwerk/realtime'
export default defineDurableObject({
name: 'Leaderboard',
methods: {
async addReferral(userId: string) {
const current = (await this.ctx.storage.get(userId)) ?? 0
await this.ctx.storage.put(userId, current + 1)
// Notify all connected clients
this.broadcast(JSON.stringify({
type: 'update',
userId,
count: current + 1
}))
return current + 1
},
async getTop(limit = 10) {
const all = await this.ctx.storage.list()
return [...all.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, limit)
},
},
})
import { durableObjects } from '@cloudwerk/bindings'
export async function GET() {
const leaderboard = durableObjects.Leaderboard.get('global')
const top = await leaderboard.getTop(10)
return Response.json(top)
}
Chapter 5

Image Uploads

Let users add profile pictures and shareable cards.

R2 gives you S3-compatible object storage with zero egress fees. Upload files directly, then queue heavy processing like thumbnails and social cards for background execution.

+ R2 Storage Image Processing
Cloudwerk Project
import { r2, queues } from '@cloudwerk/bindings'
export async function POST(request: Request) {
const formData = await request.formData()
const file = formData.get('avatar') as File
const key = `avatars/${crypto.randomUUID()}`
await r2.put(key, file.stream(), {
httpMetadata: { contentType: file.type },
})
// Generate thumbnail + social card async
await queues.imageProcessing.send({
key,
operations: ['thumbnail-200', 'social-card']
})
return Response.json({ key, url: `/cdn/${key}` })
}
import { defineQueue } from '@cloudwerk/queue'
import { services } from '@cloudwerk/bindings'
export default defineQueue<{ key: string; operations: string[] }>({
name: 'imageProcessing',
config: {
batchSize: 5, // Process 5 images at a time
maxRetries: 3,
},
async process(message) {
const { key, operations } = message.body
for (const op of operations) {
await services.images.process(key, op)
}
},
})
Chapter 6

External Integrations

Notify our Discord when someone hits a milestone.

Triggers let you react to events across your system. When a user hits 10 referrals, fire a webhook to Discord. When a payment succeeds, send a receipt. Clean, decoupled, testable.

+ Event Triggers Webhooks
Cloudwerk Project
import { defineTrigger } from '@cloudwerk/triggers'
import { db } from '@cloudwerk/bindings'
export default defineTrigger({
name: 'referral-milestone',
event: 'referral.milestone',
async handler({ userId, count, email }) {
// Notify Discord
await fetch(env.DISCORD_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: `🎉 **${email}** just hit **${count} referrals**!`,
}),
})
// Award a badge
await db.prepare(`
INSERT INTO badges (user_id, badge, awarded_at)
VALUES (?, ?, datetime('now'))
`).bind(userId, `referrals-${count}`).run()
},
})
// In your leaderboard logic
import { emit } from '@cloudwerk/triggers'
const count = await leaderboard.addReferral(userId)
if (count === 10 || count === 50 || count === 100) {
await emit('referral.milestone', { userId, count, email })
}
Chapter 7

Scale for Launch Day

Launch is tomorrow. Let's extract heavy services.

Your email and image services are getting heavy. Extract them to dedicated workers with a single config change. Same code. Same imports. Cloudwerk handles the service bindings automatically.

+ Service Extraction Service Bindings
Cloudwerk Project
import { defineConfig } from '@cloudwerk/core'
export default defineConfig({
services: {
extract: ['email', 'images'],
},
})
Deploy
█
BEFORE (Local Mode)
Main Worker
RoutesEmailImagesQueues
→
AFTER (Extracted)
Main Worker
RoutesQueuesObjects
Email Service
Images Service
Chapter 8

Admin Dashboard

Manage your waitlist and send announcements.

Add authentication in minutes. Cloudwerk's convention-based auth supports OAuth providers, credentials, passkeys, and role-based access control. Protect routes with a single function call.

+ Authentication OAuth RBAC
Cloudwerk Project
import { defineProvider, google } from '@cloudwerk/auth'
export default defineProvider(
google({
clientId: { env: 'GOOGLE_CLIENT_ID' },
clientSecret: { env: 'GOOGLE_CLIENT_SECRET' },
})
)
import { defineRBAC } from '@cloudwerk/auth'
export default defineRBAC({
roles: {
admin: ['*'],
user: ['waitlist:read'],
},
defaultRole: 'user',
})
import { requireRole } from '@cloudwerk/auth'
export default function AdminLayout({ children }) {
requireRole('admin')
return (
<div className="admin-layout">
<nav>{/* Admin nav */}</nav>
<main>{children}</main>
</div>
)
}
Chapter 9

Your App, Production-Ready

The journey is complete.

What started as a simple landing page is now a full-stack edge application with real-time features, background processing, file storage, external integrations, and secure admin access.

THE FINAL ARCHITECTURE
app/
├── page.tsx Landing page
├── refer/[code]/ Referral pages
├── admin/ Protected admin (layout + pages)
├── api/ API routes
├── auth/ Google OAuth + RBAC
├── services/ 2 services (extracted)
│ ├── email/ → mylaunch-email-service
│ └── images/ → mylaunch-images-service
├── queues/ 2 queues
│ ├── emails.ts Async email delivery
│ └── images.ts Background processing
├── objects/ 1 durable object
│ └── leaderboard.ts Real-time referral tracking
└── triggers/ 1 trigger
└── milestones.ts Discord notifications
$ cloudwerk deploy
✓ Deployed 3 workers in 5.3s
8 Routes•2 Services•2 Queues•1 Durable Object•1 Trigger

One codebase. One deploy command. Zero DevOps complexity.

Everything You Need

Cloudwerk provides all the primitives for building full-stack edge applications.

📁

File-Based Routing

Intuitive routing powered by your file structure. Create page.tsx and route.ts files.

⚡

Compiles to Hono

Your routes compile to Hono, giving you the performance of one of the fastest frameworks.

☁️

Cloudflare Native

First-class support for D1, KV, R2, Durable Objects, Queues, and all Cloudflare primitives.

🌍

Edge-First

Deploy to 300+ edge locations worldwide. Your code runs milliseconds from your users.

🔐

Built-in Auth

OAuth providers, session management, RBAC, and multi-tenancy out of the box.

📦

Service Extraction

Start with co-located services, extract to separate Workers when you scale.

📬

Queue Integration

Type-safe queue consumers with Zod validation, retries, and dead letter queues.

⏰

Event Triggers

Cron jobs, webhooks, R2 events, email handlers, and more—all with type safety.

Cloudwerk vs Traditional Architecture

Feature Cloudwerk Traditional
Deployment Edge (300+ locations) Single region
Cold Start ~0ms (no containers) 100ms-10s
Scaling Automatic, instant Manual or delayed auto-scale
Database D1 (distributed SQLite) Centralized Postgres/MySQL
State Management Durable Objects Redis/External store
Queue Processing Cloudflare Queues SQS/RabbitMQ/Redis
File Storage R2 (S3-compatible) S3/GCS
Auth Built-in + Workers KV External service

Ready to Build on the Edge?

Get started with Cloudwerk in minutes. Create your first edge-native application today.

Terminal
$ npx @cloudwerk/create-app my-app
$ cd my-app
$ cloudwerk dev
✓ Routes compiled (3 routes)
✓ Database ready (D1)
✓ Types generated
🚀 Server running at http://localhost:8787