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 Routes2 Services2 Queues1 Durable Object1 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