Skip to main content

Command Palette

Search for a command to run...

Cloudflare Page Functions: Building a Serverless Backend for Static Website

A step-by-step tutorial covering Page Functions implementation, deployment, and best practices.

Updated
6 min read

This tutorial shows how to add and deploy a serverless backend to a static website by using Pages Functions. At the end of this tutorial, you'll be able to:

  • Understand the importance of having a serverless backend in a static website
  • Identify which features require a server-side processing
  • Configure and deploy a serverless backend by using Cloudflare Page Functions
  • Implement HTTP methods (POST, GET, PUT, DELETE)

Prerequisites

Before starting this tutorial, you should have:

  • Basic knowledge of HTML and JavaScript
  • Basic knowledge of a backend server environment (Node.js, Python, PHP, etc.)
  • A Cloudflare account (free tier is sufficient)
  • A Cloudflare Pages project deployed on the Cloudflare dashboard
  • Basic understanding of HTTP and API requests

A Serverless Backend in a Static Website

Static websites are limited to what JavaScript can do on the client-side. Sensitive actions like form submissions, payment processing, database operations, or calling a third-party API become risky as the credentials or private data are fully exposed in the browser. These features are essential for most modern websites, yet implementing them securely in a static website seems impossible. So, how can we add these essentials features while keeping the website secure for the users? A serverless backend - provided by Cloudflare Page Functions - is one of the most effective and easiest solution.

What is Cloudflare Page Functions?

Cloudflare Page Functions allows to deploy server-side code alongside the static website without running a dedicated server. Built on the same infrastructure as Cloudflare Workers, Page Functions are specifically designed to work seamlessly with static sites hosted on Cloudflare Pages. They automatically handle incoming HTTP requests to the specified routes, making it simple to add backend functionality to the static website.

Step-by-step Implementation

Create a Function

  1. Create the functions directory

    At the root of the Pages project, create a directory called functions.

    /functions
    /assets
    index.html
    style.css
    script.js
    
  2. Understanding Routes

    Each JavaScript or TypeScript file in the functions directory becomes a serverless function that automatically deploys a Worker on Cloudflare Pages.

    The file name and location determines which URL route the function handles.

    Index route: A file named index.js handles requests to /

    /functions
      index.js        → /
    

    Basic routes: A file named hello.js handles requests to /hello

    /functions
      hello.js        → /hello
    

    Nested routes: A file named users.js in the /api subdirectory handles requests to /api/hello

    /functions
      /api
        users.js      → /api/users
    

    Dynamic routes: A file named [id].js in the /api subdirectory handles parameterized requests. The value inside the brackets becomes available in the function as a parameter.

    /functions
      /api
        [id].js       → /api/123, /api/456, /api/any-value
    
  3. Write the Function

    Each function file must export a handler method that processes incoming requests. The handler receives a context object and must return a Response or a Promise object.

    Basic handler example:

    export async function onRequest(context) {
      const { id, functionPath } = context;
      
      return new Response(`You requested ID: \({id} from \){functionPath} route`);
    }
    

    The context object contains:

    • request - incoming HTTP request
    • functionPath - path of the request
    • env - environment variables and bindings
    • params - dynamic route parameters
    • data - data passed

HTTP method-specific handlers

The Page Functions can support several HTTP request methods such as GET, POST, PATCH, PUT, and DELETE. The handler name must start with onRequest name, followed by the HTTP method name.

Available handlers:

  • onRequest - Invoked on all requests regardless of method
  • onRequestGet - Invoked on GET requests (retrieving data)
  • onRequestPost - Invoked on POST requests (creating data)
  • onRequestPut - Invoked on PUT requests (updating data)
  • onRequestPatch - Invoked on PATCH requests (partially updating data)
  • onRequestDelete - Invoked on DELETE requests (removing data)

Handle all request methods:

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

Handle specific methods:

// GET - Retrieve data
export async function onRequestGet(context) {
  return new Response('Fetching data...');
}

// POST - Create new data
export async function onRequestPost(context) {
  const data = await context.request.json();
  return new Response('Data created!');
}

// PUT - Update existing data
export async function onRequestPut(context) {
  const data = await context.request.json();
  return new Response('Data updated!');
}

// DELETE - Remove data
export async function onRequestDelete(context) {
  return new Response('Data deleted!');
}

Note: Multiple handlers can be exported from the same file. When a request arrives, Cloudflare will invoke the most specific handler that matches the request method.

Local development

Before deploying to Cloudflare, Pages Functions can be tested locally using Wrangler, a Cloudflare's command-line tool.

  1. Install Wrangler

    Ensure Node.js and npm are installed on the machine.

    • Install Wrangler globally:
    npm install -g wrangler
    
    • Verify the installation:
    wrangler --version
    
  2. (Optional) Add Wrangler configuration

    For basic local development, Wrangler works without additional configuration. However, if the Pages needs environment variables or specific settings, a wrangler.toml file must be created at the project root:

    name = "my-pages-project"
    compatibility_date = "2024-01-29"
    
    [vars]
    ENVIRONMENT = "development"
    
  3. Run Pages project locally

    In the project root run Wranger development command to start the local development server:

    wrangler pages dev .
    

    Or specify a specific directory:

    wrangler pages dev ./public
    

    Wrangler will:

    • Serve the static files
    • Run the Functions locally
    • Hot-reload when you make changes

    By default, the project will be available at http://localhost:8788 .

  4. Test the Function

    Once the server is running, test the functions using a browser or tools like curl:

    Using the browser:

    http://localhost:8788/hello
    http://localhost:8788/api/users
    

    Using curl:

    # Test GET request
    curl http://localhost:8788/api/users
    
    # Test POST request
    curl -X POST http://localhost:8788/api/users \
      -H "Content-Type: application/json" \
      -d '{"name": "John Doe"}'
    

Deployment

The Pages Functions are automatically deployed when the Pages project is deployed to Cloudflare. There are two main deployment methods:

  • By Git provider (recommended) - this method automatically deploys the project whenever push changes are performed in the repository.
  • By Wrangler CLI - this method can be used for quick deployments without connecting a Git repository.

Best Practices

  • Organize the Functions by feature - group related functions in folders (e.g., /api/users, /api/posts).
  • Implement the most appropriate HTTP method - use the pre-defined handlers (e.g., onRequestGet, onRequestPost) for each HTTP method.
  • Protect sensitive data - store secrets, API keys, tokens or credentials as environment variables and access them via context.env.
  • Use the appropriate HTTP status codes - Use 200 for success, 400 for bad requests, 500 for server errors.
  • Keep Functions lightweight - minimize external dependencies, and cache responses when appropriate.

Cloudflare

Part 1 of 2

A hands-on series covering Cloudflare's ecosystem: securing web forms, setting up infrastructure, and wiring Cloudflare into your development and analytics engineering stack.

Up next

How to Implement Cloudflare Turnstile for Web Form Protection

A step-by-step tutorial covering setup, frontend integration, and server-side validation of Cloudflare Turnstile