Cloudflare Workers
Platform
Cloudflare Workers
Overview
Cloudflare Workers is a serverless execution environment running on the world's largest edge network, providing an ultra-fast and highly available computing platform based on the V8 JavaScript engine. By enabling distributed execution across 330+ global locations, it processes requests at geographically optimal locations, dramatically reducing latency. As of 2025, with WebAssembly support, TypeScript enhancements, upcoming Containers integration, and a comprehensive edge computing ecosystem including Durable Objects, R2 Storage, and D1 Database, it's rapidly evolving as a next-generation platform that revolutionizes traditional serverless concepts.
Details
Cloudflare Workers 2025 edition delivers performance that sets it apart from traditional container-based serverless platforms through V8 Isolate technology, achieving 0ms cold starts and advanced isolation. Particularly noteworthy is the planned Containers integration scheduled for mid-2025, which will enable running traditional Node.js environments and Docker containers directly at the edge. With sophisticated development experience through Wrangler CLI, stateful processing via Durable Objects, object storage with R2 Storage, edge database with D1 Database, and complete integration with web frameworks like Hono, it provides a complete platform for building full-stack applications at the edge.
Key Features
- Edge Computing: Distributed execution across 330+ global locations
- V8 Isolate: 0ms cold starts and instant execution
- WebAssembly Support: Support for Rust, Go, C++, and other languages
- Durable Objects: Stateful edge computing capabilities
- R2 Storage: S3-compatible object storage
- D1 Database: Edge SQLite database
Latest 2025 Features
- Containers Integration: Docker/Node.js container edge execution (mid-2025)
- Enhanced Wrangler: Improved CLI and deployment experience
- Advanced Analytics: Real-time analytics and performance monitoring
- WebAssembly Optimization: Faster WASM execution and new language support
- Framework Integration: Deep integration with Hono, Next.js, Astro, and more
Advantages and Disadvantages
Advantages
- Ultra-low latency through world's premier edge network
- 0ms cold starts and fast execution via V8 Isolate technology
- Automatic scaling and high availability
- Multi-language support through WebAssembly
- Comprehensive edge computing ecosystem
- Excellent developer experience and sophisticated Wrangler CLI
- Competitive pricing and generous free tier
Disadvantages
- Execution time limits (CPU time: 10ms-50ms, wall time: 15 minutes)
- Memory constraints (128MB) limiting processing capabilities
- Partial Node.js compatibility restrictions (improving with 2025 Containers integration)
- Constraints on complex database operations and file I/O
- Relatively new ecosystem with limited third-party tools
- Complexity in debugging and local development
Reference Pages
- Cloudflare Workers Official Site
- Cloudflare Workers Documentation
- Wrangler CLI Documentation
- Cloudflare Developers Discord
Code Examples
Setup and Basic Configuration
# Install Wrangler CLI
npm install -g wrangler
# Authenticate with Cloudflare account
wrangler login
# Create a new Worker project
wrangler init my-worker
# Start local development server
wrangler dev
# Deploy to production
wrangler deploy
// src/index.js - Basic Worker
export default {
async fetch(request, env, ctx) {
// Get request information
const url = new URL(request.url);
const userAgent = request.headers.get('User-Agent');
const cfRay = request.headers.get('CF-Ray');
const country = request.cf?.country || 'Unknown';
// Set CORS headers
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
};
// Handle preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 200,
headers: corsHeaders,
});
}
try {
// Route handling
switch (request.method) {
case 'GET':
return handleGet(request, env);
case 'POST':
return handlePost(request, env);
default:
return new Response('Method not allowed', {
status: 405,
headers: corsHeaders
});
}
} catch (error) {
console.error('Error processing request:', error);
return new Response(JSON.stringify({
error: 'Internal server error',
ray: cfRay
}), {
status: 500,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
}
};
async function handleGet(request, env) {
const url = new URL(request.url);
const path = url.pathname;
if (path === '/api/info') {
return new Response(JSON.stringify({
message: 'Hello from Cloudflare Workers!',
timestamp: new Date().toISOString(),
location: request.cf?.colo,
country: request.cf?.country,
ray: request.headers.get('CF-Ray')
}), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not found', { status: 404 });
}
async function handlePost(request, env) {
const body = await request.json();
return new Response(JSON.stringify({
received: body,
processed_at: new Date().toISOString()
}), {
headers: { 'Content-Type': 'application/json' }
});
}
HTTP APIs and Routing
// src/index.ts - TypeScript + Hono Framework
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { jwt } from 'hono/jwt';
type Bindings = {
DB: D1Database;
BUCKET: R2Bucket;
JWT_SECRET: string;
API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
// Middleware setup
app.use('*', cors());
app.use('*', logger());
// Protected routes setup
app.use('/api/protected/*', async (c, next) => {
const jwtMiddleware = jwt({
secret: c.env.JWT_SECRET,
});
return jwtMiddleware(c, next);
});
// Public API
app.get('/api/health', (c) => {
return c.json({
status: 'healthy',
timestamp: new Date().toISOString(),
worker_location: c.req.header('CF-Ray')?.split('-')[1] || 'unknown',
country: c.req.header('CF-IPCountry') || 'unknown'
});
});
// RESTful API
app.get('/api/users/:id', async (c) => {
const userId = c.req.param('id');
// Get user information from D1 database
const user = await c.env.DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(userId).first();
if (!user) {
return c.json({ error: 'User not found' }, 404);
}
return c.json(user);
});
app.post('/api/users', async (c) => {
const userData = await c.req.json();
const result = await c.env.DB.prepare(
'INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)'
).bind(
userData.name,
userData.email,
new Date().toISOString()
).run();
return c.json({
id: result.meta.last_row_id,
message: 'User created successfully'
}, 201);
});
// Protected API
app.get('/api/protected/profile', async (c) => {
const payload = c.get('jwtPayload');
return c.json({
user_id: payload.sub,
message: 'This is a protected endpoint'
});
});
export default app;
Database Integration and Data Processing
// Database operations (D1 Database)
app.get('/api/posts', async (c) => {
try {
// Pagination
const page = parseInt(c.req.query('page') || '1');
const limit = parseInt(c.req.query('limit') || '10');
const offset = (page - 1) * limit;
// Execute SQL query in D1
const posts = await c.env.DB.prepare(`
SELECT
id, title, content, author, created_at, updated_at
FROM posts
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`).bind(limit, offset).all();
const totalCount = await c.env.DB.prepare(
'SELECT COUNT(*) as count FROM posts'
).first();
return c.json({
posts: posts.results,
pagination: {
page,
limit,
total: totalCount.count,
pages: Math.ceil(totalCount.count / limit)
}
});
} catch (error) {
console.error('Database error:', error);
return c.json({ error: 'Database error' }, 500);
}
});
// R2 Storage integration
app.post('/api/upload', async (c) => {
try {
const formData = await c.req.formData();
const file = formData.get('file') as File;
if (!file) {
return c.json({ error: 'No file provided' }, 400);
}
// Generate file name
const fileName = `uploads/${Date.now()}-${file.name}`;
// Upload file to R2
await c.env.BUCKET.put(fileName, file.stream(), {
httpMetadata: {
contentType: file.type
}
});
// Save file information to database
await c.env.DB.prepare(`
INSERT INTO files (name, original_name, size, content_type, uploaded_at)
VALUES (?, ?, ?, ?, ?)
`).bind(
fileName,
file.name,
file.size,
file.type,
new Date().toISOString()
).run();
return c.json({
message: 'File uploaded successfully',
fileName,
size: file.size
});
} catch (error) {
console.error('Upload error:', error);
return c.json({ error: 'Upload failed' }, 500);
}
});
Authentication and Security
// JWT authentication system
import { sign, verify } from 'hono/jwt';
import { createHash } from 'crypto';
// Login functionality
app.post('/api/auth/login', async (c) => {
try {
const { email, password } = await c.req.json();
// User authentication
const user = await c.env.DB.prepare(
'SELECT id, email, password_hash FROM users WHERE email = ?'
).bind(email).first();
if (!user) {
return c.json({ error: 'Invalid credentials' }, 401);
}
// Password verification
const passwordHash = createHash('sha256')
.update(password + c.env.JWT_SECRET)
.digest('hex');
if (passwordHash !== user.password_hash) {
return c.json({ error: 'Invalid credentials' }, 401);
}
// Generate JWT token
const token = await sign({
sub: user.id,
email: user.email,
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24) // 24 hours
}, c.env.JWT_SECRET);
return c.json({
token,
user: {
id: user.id,
email: user.email
}
});
} catch (error) {
console.error('Login error:', error);
return c.json({ error: 'Login failed' }, 500);
}
});
// Rate Limiting (using Durable Objects)
app.use('/api/*', async (c, next) => {
const clientIP = c.req.header('CF-Connecting-IP') || 'unknown';
const rateLimitKey = `rate_limit:${clientIP}`;
// Get rate limit information from KV
const requests = await c.env.KV.get(rateLimitKey);
const requestCount = requests ? parseInt(requests) : 0;
if (requestCount >= 100) { // 100 requests per hour
return c.json({ error: 'Rate limit exceeded' }, 429);
}
// Update request count
await c.env.KV.put(rateLimitKey, (requestCount + 1).toString(), {
expirationTtl: 3600 // 1 hour
});
await next();
});
Event-Driven Architecture
// Stateful processing using Durable Objects
export class ChatRoom {
constructor(private state: DurableObjectState, private env: Env) {}
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === '/websocket') {
return this.handleWebSocket(request);
}
return new Response('Not found', { status: 404 });
}
async handleWebSocket(request: Request): Promise<Response> {
const [client, server] = new WebSocketPair();
server.accept();
// Manage connected WebSockets
server.addEventListener('message', async (event) => {
const message = JSON.parse(event.data);
// Broadcast message
this.state.getWebSockets().forEach((ws) => {
ws.send(JSON.stringify({
type: 'message',
data: message,
timestamp: new Date().toISOString()
}));
});
});
this.state.acceptWebSocket(server);
return new Response(null, {
status: 101,
webSocket: client,
});
}
}
// Background processing and scheduling
export default {
async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext): Promise<void> {
// Scheduled task execution
console.log('Scheduled task executing at:', new Date().toISOString());
// Database cleanup
await env.DB.prepare(`
DELETE FROM sessions
WHERE expires_at < datetime('now')
`).run();
// R2 storage temporary file cleanup
const objects = await env.BUCKET.list({
prefix: 'temp/',
});
for (const object of objects.objects) {
const ageMs = Date.now() - object.uploaded.getTime();
if (ageMs > 24 * 60 * 60 * 1000) { // Older than 24 hours
await env.BUCKET.delete(object.key);
}
}
},
// Queue processing
async queue(batch: MessageBatch<any>, env: Env): Promise<void> {
for (const message of batch.messages) {
try {
await processQueueMessage(message.body, env);
message.ack();
} catch (error) {
console.error('Queue processing error:', error);
message.retry();
}
}
}
};
async function processQueueMessage(data: any, env: Env): Promise<void> {
// Asynchronous message processing
switch (data.type) {
case 'email':
await sendEmail(data.payload, env);
break;
case 'webhook':
await processWebhook(data.payload, env);
break;
default:
console.warn('Unknown message type:', data.type);
}
}
Monitoring and Performance Optimization
// Custom metrics and logging
app.use('*', async (c, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
const status = c.res.status;
const method = c.req.method;
const path = c.req.path;
// Send custom metrics
console.log(JSON.stringify({
type: 'access_log',
method,
path,
status,
duration,
timestamp: new Date().toISOString(),
ray: c.req.header('CF-Ray'),
country: c.req.header('CF-IPCountry')
}));
// Send to Analytics Engine
if (c.env.ANALYTICS) {
c.env.ANALYTICS.writeDataPoint({
blobs: [method, path],
doubles: [duration],
indexes: [status.toString()]
});
}
});
// Error handling and alerts
app.onError((err, c) => {
console.error('Application error:', {
error: err.message,
stack: err.stack,
url: c.req.url,
method: c.req.method,
ray: c.req.header('CF-Ray'),
timestamp: new Date().toISOString()
});
return c.json({
error: 'Internal server error',
ray: c.req.header('CF-Ray')
}, 500);
});
// Health checks and performance monitoring
app.get('/api/metrics', async (c) => {
const metrics = {
timestamp: new Date().toISOString(),
worker_info: {
location: c.req.header('CF-Ray')?.split('-')[1] || 'unknown',
country: c.req.header('CF-IPCountry') || 'unknown',
colo: c.req.header('CF-Colo') || 'unknown'
},
system_info: {
memory_usage: 'not_available', // Not available in Workers
uptime: 'not_applicable' // Stateless
},
services: {
database: await checkDatabase(c.env.DB),
storage: await checkStorage(c.env.BUCKET),
kv: await checkKV(c.env.KV)
}
};
return c.json(metrics);
});
async function checkDatabase(db: D1Database): Promise<string> {
try {
await db.prepare('SELECT 1').first();
return 'healthy';
} catch (error) {
return 'unhealthy';
}
}
async function checkStorage(bucket: R2Bucket): Promise<string> {
try {
await bucket.head('health-check');
return 'healthy';
} catch (error) {
return 'healthy'; // File not existing is normal
}
}
async function checkKV(kv: KVNamespace): Promise<string> {
try {
await kv.get('health-check');
return 'healthy';
} catch (error) {
return 'unhealthy';
}
}