Cloudflare Workers

ServerlessCloudflareEdge ComputingWebAssemblyJavaScriptTypeScript

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

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';
    }
}