Dan Cowell Engineering Manager
Osaka, Japan (mostly)


Lessons learned building this site with Cloudflare Pages

Published Sunday the 9th of January, 2022

Cloudflare Pages is a new Jamstack hosting service built on the Cloudflare Workers runtime. I chose it as the backend for this site largely because of timing. Cloudflare's Full Stack Week (and the announcement of Pages) happened right as I was gearing up to build this blog and it seemed like a good opportunity to try out the new service.

I have used Workers in the past for company projects that required some edge computing magic, but Pages is an entirely different beast. It brings a managed CI/CD pipeline, one-click web analytics, worker deployment and server-side rendering together into one cohesive product.

Here are a few of the things I've learned along the way. Bear in mind that as of the time of writing (early January 2022) Pages is a beta product, so many of these rough edges may be smoothed out by the time you're reading this.

Workers Platform features aren't tightly integrated with supported frameworks

Cloudflare's KV and Durable Objects are powerful and easy-to-use persistence tools which are supported on the Pages platform. Unfortunately they are not yet well integrated with the various frameworks that can be used to build Pages applications.

Many of these frameworks have their own conventions for server-side rendering and serverless functions. These implementations work flawlessly out of the box on the Pages platform, which is great to see.

That said, at the time of writing platform features like KV and Durable Objects bindings are not easily accessible from serverless functions defined inside these frameworks. If you want to take advantage of these APIs you must declare your serverless functions in the functions directory which is managed and built by Pages, outside of your framework project.

This can be confusing for new users who may expect full access to the power of the Workers platform within their framework's serverless functions.

Hopefully we'll see a consistent API for interacting with Cloudflare's platform made available in these framework packages or as an optional stand-alone dependency as Pages gets closer to a GA release.

Builds can be slow, but they're getting faster

On the standard Pages plan it can take up to 2-3 minutes to initialize the build environment before even starting your build.

This can be frustrating, but it is changing rapidly. There is already an opt-in fast builds beta which drops that time down to a couple of seconds. This site is in the beta, and currently builds and deploys in ~48 seconds end-to-end, incuding the time it takes to initialize the build environment and clone the git repo.

Pages will likely have the fastest deploys of any Jamstack platform once fast builds go GA.

Failed: an internal error occurred

This error can happen for a bunch of different reasons and can be infuriating when it happens. Here are all of the ones I've run into while developing for Pages:

Misconfigured build output directory

If Pages can't find your built application in the directory configured in your project settings it will fail at the final deployment step with this error.

The majority of people who run into this error find that this is the problem.

Using platform APIs in the global scope

The Pages platform will fail with this error if you try to deploy a Function which uses some runtime APIs in the global scope. For example, this function reliably fails to deploy:

// functions/broken.js

const errorResponse = new Response("", { status: 404 });

export const onRequestGet = () => {
return errorResponse;

This similar function will deploy successfully:

// functions/working.js

export const onRequestGet = () => {
const errorResponse = new Response("", { status: 404 });

return errorResponse;

If you want to minimise code duplication you may declare helper functions in the global scope:

// functions/working.js

const notFound = () => new Response("", { status: 404 });

export const onRequestGet = () => notFound();

_headers configuration doesn't apply to Functions

If you are relying on the _headers config file to apply custom headers to your Cloudflare Pages site, you may notice missing headers on responses from Functions or server-side rendered pages.

Currently the Pages runtime only applies headers defined in the _headers file to static assets, so if you want to return custom headers on Functions responses or server-side rendered pages you must attach them to the Response object yourself.

Cloudflare Pages still has some rough edges, particularly in the developer experience and documentation space. That said, it's blazing fast and the community support around it is second to none.

If you are working on a Pages project I highly recommend joining the Cloudflare Developers Discord server. The product team are highly engaged and deeply committed to building a polished product. It's fantastic to see.

I'm looking forward to seeing how Pages continues to evolve as it gets closer to GA release.