Cloudflare Workers & Pages Functions — Birdor Cloudflare Tutorial Series (Part 5)

A clear, calm, developer-friendly introduction to Cloudflare Workers and Pages Functions. Learn how edge compute works, how to create your first functions, how routing works, and how Workers fit your Hugo or JAMstack workflow.

Cloudflare Workers allow developers to run JavaScript and TypeScript directly at the edge — close to users and without maintaining servers. Pages Functions provide the same compute model inside Cloudflare Pages projects, giving static sites like Hugo access to dynamic capabilities such as authentication, APIs, routing logic, and integrations.

This tutorial offers a calm, practical introduction to Workers and Functions with examples that fit naturally into Hugo and JAMstack projects. No prior serverless experience is required.

1. Understanding Cloudflare’s Edge Compute Model

Traditional serverless platforms execute code in centralized regions. Cloudflare Workers run code in hundreds of edge data centers, meaning:

  • lower latency
  • no cold starts
  • consistent performance worldwide
  • built-in isolation and security
  • no need to choose regions
  • instant global deployment

Workers use the V8 engine directly, not Node.js, which keeps them lightweight, fast, and predictable.

2. Workers vs Pages Functions (A Clear Distinction)

Cloudflare offers two ways to run serverless logic.

2.1 Cloudflare Workers

Standalone serverless applications.

Use cases:

  • APIs
  • proxies
  • routing logic
  • SSR frameworks
  • authentication flows
  • cron jobs

Deployment:

  • via Wrangler CLI
  • flexible routing
  • custom domains

2.2 Pages Functions

Serverless functions specifically for Cloudflare Pages projects.

Use cases:

  • small APIs for your Hugo site
  • form submissions
  • dynamic content
  • proxying external services
  • authenticated endpoints

Structure:

/functions
/api
hello.js
contact.js

Functions automatically map to routes.
They deploy together with your Hugo build.

If you’re deploying a Hugo site on Cloudflare Pages, Pages Functions are the simplest way to add dynamic behavior.

3. Creating Your First Pages Function

Inside your Hugo project repository:

mkdir -p functions/api

Create a file:

functions/api/hello.js

export async function onRequest(context) {
  return new Response("Hello from Cloudflare Pages Functions!");
}

Deploy your Pages project, then visit:

/api/hello

You now have your first serverless endpoint running on Cloudflare.

4. Understanding the Function Context

Cloudflare provides a context object with:

  • request – incoming Request object
  • env – environment variables (bindings)
  • params – route parameters
  • next() – middleware continuation

Example:

export async function onRequest(context) {
  const url = new URL(context.request.url);
  return new Response(`You visited: ${url.pathname}`);
}

This lightweight API is intentionally simple and browser-compatible.

5. Creating Dynamic Routes

Dynamic parameters work through folder names.

Example:

functions/user/[id].js

export async function onRequest(context) {
  const userId = context.params.id;
  return new Response(`User ID: ${userId}`);
}

Route:

/user/42

Dynamic routing is a strength of Pages Functions for small APIs and utilities.

6. Using fetch() to call APIs

Pages Functions support the standard fetch() API.

Example: calling GitHub’s API:

export async function onRequest() {
  const res = await fetch("https://api.github.com/repos/cloudflare/workers");
  const data = await res.json();
  return new Response(JSON.stringify(data, null, 2), {
    headers: { "Content-Type": "application/json" }
  });
}

This makes Pages Functions ideal as a middle layer between your Hugo site and external APIs.

7. Using Environment Variables (Bindings)

Environment variables let you store secrets and configuration.

7.1 Add bindings in Cloudflare

Cloudflare Pages → Your Project → Settings → Environment Variables

Example:

API_TOKEN = super_secret_value

7.2 Access in Functions

export async function onRequest(context) {
  const token = context.env.API_TOKEN;
  return new Response(`Token length: ${token.length}`);
}

Bindings never leak to the browser unless you deliberately return them.

8. Middleware: Reusable Logic

Middleware allows shared logic, such as authentication.

Example: functions/_middleware.js

export async function onRequest(context) {
  const apiKey = context.request.headers.get("x-api-key");
  if (apiKey !== context.env.SECRET_KEY) {
    return new Response("Unauthorized", { status: 401 });
  }
  return await context.next();
}

This applies to all functions automatically.

9. Worker Cron Triggers (Scheduled Jobs)

Example use cases:

  • clean stale KV entries
  • scheduled sync with external APIs
  • periodic database updates

Define in your Worker’s config:

[triggers]
crons = ["0 */6 * * *"]  # every 6 hours

A scheduled Worker function might:

export default {
  async scheduled(event, env, ctx) {
    // do background tasks
  }
}

Cron triggers are not available in Pages Functions — only in Workers.

10. Building API Routes for Hugo

Hugo remains static, but Pages Functions extend it:

Examples:

Contact form endpoint:

functions/api/contact.js

export async function onRequest({ request }) {
  const data = await request.formData();
  const email = data.get("email");
  const message = data.get("message");

  // Send to an external service or email provider
  return new Response("OK");
}

Search endpoint using Meilisearch:

functions/api/search.js

export async function onRequest(context) {
  const query = new URL(context.request.url).searchParams.get("q");
  const res = await fetch(`${context.env.SEARCH_URL}?q=${query}`);
  return new Response(await res.text(), {
    headers: { "Content-Type": "application/json" }
  });
}

Proxy external API:

export async function onRequest() {
  return fetch("https://api.example.com/data");
}

Pages Functions turn your static Hugo site into a full-featured JAMstack app.

11. Workers: When You Need More Control

Use Workers instead of Pages Functions when you need:

  • custom routing
  • scheduled cron jobs
  • Durable Objects (stateful logic)
  • integration with R2, D1, or KV
  • SSR frameworks (Astro, Qwik, SvelteKit adapters exist)
  • a standalone API service
  • no Pages deployment

Workers are deployed with wrangler:

npm install -g wrangler
wrangler login
wrangler init my-worker
wrangler publish

Workers offer the full power of Cloudflare’s serverless platform.

12. Integrating Workers With Pages

Cloudflare lets you apply Workers to Pages using:

  • Worker overrides
  • custom routing patterns
  • Workers for API endpoints while Pages handles static files

This hybrid model is flexible and efficient.

13. Best Practices for Hugo + Pages Functions

  • Keep Functions small and stateless
  • Use bindings for secrets
  • Cache API responses with Cache API where appropriate
  • Avoid heavy CPU work — edge compute prefers lightweight logic
  • Wrap shared logic in middleware
  • Serve errors responsibly (don’t expose internals)
  • Use structured JSON responses
  • Add logs in development (wrangler pages dev)

For most developer tools, dashboards, and blogs, Pages Functions provide all the dynamic features needed.

14. Troubleshooting

14.1 Function not running?

Ensure:

  • file is inside the /functions directory
  • file extension is .js or .ts
  • export name is correct (onRequest)

14.2 Environment variable undefined?

Check:

  • bindings exist in both Preview and Production environments
  • variable name matches exactly

14.3 Route not matching?

Verify:

  • folder structure matches expected URL path
  • dynamic segments use [param] syntax

15. Conclusion and What’s Next

In this chapter, we explored:

  • Cloudflare’s edge compute model
  • differences between Workers and Pages Functions
  • creating serverless endpoints for Hugo
  • dynamic routes, environment variables, and middleware
  • API integrations and scheduled jobs
  • when to use Workers instead of Functions

Pages Functions turn a static Hugo site into a dynamic, globally distributed application — without traditional backends or servers.

Next chapter:
Cloudflare Tutorial Series — Part 6: KV, R2, and D1 Storage (A Practical Guide to Edge Storage)

Keep Reading

Follow the engineering thread

Get the next practical Birdor note, or browse the archive for related systems, tooling, and architecture work.

Join newsletter Browse articles