Cloudflare Page Functions: Building a Serverless Backend for Static Website
A step-by-step tutorial covering Page Functions implementation, deployment, and best practices.
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
Create the functions directory
At the root of the Pages project, create a directory called
functions./functions /assets index.html style.css script.jsUnderstanding Routes
Each JavaScript or TypeScript file in the
functionsdirectory 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.jshandles requests to//functions index.js → /Basic routes: A file named
hello.jshandles requests to/hello/functions hello.js → /helloNested routes: A file named
users.jsin the/apisubdirectory handles requests to/api/hello/functions /api users.js → /api/usersDynamic routes: A file named
[id].jsin the/apisubdirectory 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-valueWrite the Function
Each function file must export a handler method that processes incoming requests. The handler receives a
contextobject and must return aResponseor aPromiseobject.Basic handler example:
export async function onRequest(context) { const { id, functionPath } = context; return new Response(`You requested ID: \({id} from \){functionPath} route`); }The
contextobject contains:request- incoming HTTP requestfunctionPath- path of the requestenv- environment variables and bindingsparams- dynamic route parametersdata- 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 methodonRequestGet- 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.
Install Wrangler
Ensure Node.js and npm are installed on the machine.
- Install Wrangler globally:
npm install -g wrangler- Verify the installation:
wrangler --version(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.tomlfile must be created at the project root:name = "my-pages-project" compatibility_date = "2024-01-29" [vars] ENVIRONMENT = "development"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 ./publicWrangler 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.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/usersUsing 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.

