← Back to Articles

Getting Started with Cloudflare Workers

Cloudflare Workers represent a paradigm shift in how we deploy code. Instead of managing servers, you write a few lines of JavaScript that execute globally on Cloudflare's edge network. No cold starts, no scaling headaches, no servers to maintain. Deploy to 300+ data centers worldwide instantly.

What Are Cloudflare Workers?

A Cloudflare Worker is a JavaScript function that intercepts HTTP requests and generates responses. It runs on Cloudflare's edge network, meaning it executes in data centers close to your users, not in a distant data center.

This architecture enables low-latency responses, reduced bandwidth costs, and simplified deployments. Your code is cached globally. Scaling is automatic.

Setting Up Your First Worker

Install Wrangler, Cloudflare's CLI tool:

npm install -g wrangler

Create a new project:

wrangler init my-worker
cd my-worker

Your project structure includes a wrangler.toml configuration file and a src/index.js file.

Your First Worker

Here's a minimal worker that returns "Hello World":

export default {
  async fetch(request) {
    return new Response("Hello, World!");
  }
};

Deploy it:

wrangler deploy

Cloudflare assigns your worker a *.workers.dev domain. Your code is now live globally.

Routing and Path Matching

Real workers need to handle different routes. Here's how to structure routing logic:

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const pathname = url.pathname;

    if (pathname === "/api/users") {
      return handleUsers(request);
    }
    if (pathname === "/api/posts") {
      return handlePosts(request);
    }

    return new Response("Not found", { status: 404 });
  }
};

async function handleUsers(request) {
  const data = { users: ["Alice", "Bob", "Charlie"] };
  return new Response(JSON.stringify(data), {
    headers: { "content-type": "application/json" }
  });
}

Request Methods and Body Parsing

Handle different HTTP methods and parse request bodies:

export default {
  async fetch(request) {
    if (request.method === "POST") {
      const body = await request.json();
      console.log("Received:", body);
      return new Response("OK");
    }

    if (request.method === "GET") {
      return new Response("GET request received");
    }

    return new Response("Method not allowed", { status: 405 });
  }
};

Connecting to Databases

Cloudflare supports multiple databases. For SQL databases, use Hyperdrive:

export default {
  async fetch(request, env) {
    const db = env.DB;
    const result = await db.prepare(
      "SELECT * FROM users WHERE id = ?"
    ).bind(1).first();

    return new Response(JSON.stringify(result), {
      headers: { "content-type": "application/json" }
    });
  }
};

For key-value storage, use Durable Objects or KV:

const kv = env.MY_KV_NAMESPACE;
await kv.put("key", "value", { expirationTtl: 3600 });
const value = await kv.get("key");

CORS and Headers

Handle CORS for browser-based requests:

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type"
};

export default {
  async fetch(request) {
    if (request.method === "OPTIONS") {
      return new Response(null, { headers: corsHeaders });
    }

    const response = new Response("API response");
    Object.entries(corsHeaders).forEach(([key, value]) => {
      response.headers.set(key, value);
    });
    return response;
  }
};

Environment Variables

Store secrets in wrangler.toml:

[env.production]
vars = { ENVIRONMENT = "production" }
secret = { API_KEY = "your-secret-key" }

[env.development]
vars = { ENVIRONMENT = "development" }

Access them in your worker:

export default {
  async fetch(request, env) {
    const apiKey = env.API_KEY;
    const environment = env.ENVIRONMENT;
    // Use them in your code
  }
};

Caching Strategies

Cache responses to reduce latency:

export default {
  async fetch(request, env) {
    const cache = caches.default;
    const cached = await cache.match(request);

    if (cached) {
      return cached;
    }

    const response = await fetch(request);
    const cacheControl = response.headers.get("cache-control");

    if (cacheControl && cacheControl.includes("public")) {
      response.headers.set("cache-control", "max-age=3600");
      await cache.put(request, response.clone());
    }

    return response;
  }
};

Error Handling

Always wrap operations in try-catch:

export default {
  async fetch(request, env) {
    try {
      const data = await env.DB.prepare("SELECT * FROM users").all();
      return new Response(JSON.stringify(data), {
        headers: { "content-type": "application/json" }
      });
    } catch (error) {
      console.error("Error:", error);
      return new Response("Internal server error", { status: 500 });
    }
  }
};

Logging and Monitoring

Workers integrates with Cloudflare Analytics. Use console.log for debugging:

console.log("Processing request:", request.url);
console.error("Database error:", error);

View logs in the Cloudflare dashboard or via wrangler:

wrangler tail

Deployment

Deploy to production with a single command:

wrangler deploy --env production

Set up continuous deployment via GitHub Actions for automated deployments on push.

Pricing

Cloudflare Workers offers a generous free tier: 100,000 requests per day. Paid plans scale based on actual usage, typically $0.15 per million requests. For most applications, the free tier is sufficient.

Next Steps

Start with a simple API. Add database connectivity. Implement caching. Build full-stack applications without managing infrastructure. Cloudflare Workers removes operational overhead, letting you focus on building.

🛠 Go Deeper

Resources for serverless and edge computing. Affiliate links support this site.

Learning Serverless (O'Reilly)

Solid foundation for serverless architecture patterns beyond Workers.

Web Development with Node & Express

Understanding Node.js patterns makes you a better edge developer.