Skip to main content
  1. Dev Notes/

Cloudflare Pages’ Headers when Using Middleware

·567 words·3 mins

The Story Behind
#

I build several websites based with Hugo recently. But I discovered those websites got kinda mid scores on Mozilla Observatory (this one included!). Since I host those websites on Cloudflare, I can solve part of the issue my adding a _headers file to insert some of the needed headers. The one final thing to be tackle is CSP hashes for inline scripts (and styles), I need to find a way to do it since Hugo can’t do it.

This website got a grading of C (55/100) from Mozilla Observatory
The score for this website (as of March 2026)

The Broken Way
#

I found that there is a thing called “Pages Plugin” for Cloudflare Pages, I though “there must be an existing solution for this!”. Yes, but no. The one package seems to be broken now.

Because of this, I’m planning to write my own Pages Plugin. But this lead to another problem, can I keep my existing headers inside _headers?

The Questions
#

I found that this two quotes from the Cloudflare Pages docs are quite confusing:

A _headers file can have a maximum of 100 header rules.

An individual header in a _headers file can have a maximum of 2,000 characters. For managing larger headers, it is recommended to implement Pages Functions.

Limits, Cloudflare Pages docs

Warning

Custom headers defined in the _headers file are not applied to responses generated by Pages Functions, even if the request URL matches a rule defined in _headers. If you use a server-side rendered (SSR) framework, or Pages Functions (with either a folder of functions/ or an “advanced mode” _worker.js), you will likely need to attach any custom headers you wish to apply directly within that Pages Functions code.

Headers, Cloudflare Pages docs

The documentations don’t seems to have mentioned the timing to insert headers for static resources, and whether will _headers get ignored if middleware was used. These made me wonder:

When was the _headers got insert to a response of a static resource? What would happened if I use a middleware to insert new headers? I’ll attempt to answer these questions with my experiment.

The Experiment
#

First, I prepare the files needed for this experiment. These files will be deploy to Cloudflare Pages:

public/index.html
<!DOCTYPE html>
<html lang="en">
    ...
</html>
public/_headers
/*
    X-Static-Headers: 1
functions/hello.ts
export const onRequest: PagesFunction = async (request) =>
{
    const response = new Response("Hello!");
    response.headers.append("X-Function-Headers", "1");
    return response;
};
functions/_middleware.ts
export const onRequest: PagesFunction = async (request) =>
{
    const response = await request.next();
    response.headers.append("X-Middleware-Headers", "1");
    console.log("Middleware Headers:");
    console.log(JSON.stringify(Array.from(response.headers), null, 2));
    return response;
};

The Result
#

When connect to the deployed website, we got the response headers below:

Terminal
> curl -I https://headers.pages-testbed.pages.dev/
HTTP/2 200 
...
x-middleware-headers: 1
...
x-static-headers: 1
...

> curl -I https://headers.pages-testbed.pages.dev/hello
HTTP/2 200 
...
x-function-headers: 1
x-middleware-headers: 1
...

And here’s the output from the middleware:

Terminal
> npx wrangler pages deployment tail --project-name pages-testbed ...
...
GET https://headers.pages-testbed.pages.dev/ - Ok
  (log) Middleware Headers:
  (log) [
  ...
  [
    "x-middleware-headers",
    "1"
  ],
  ...
  [
    "x-static-headers",
    "1"
  ]
]

The Conclusion
#

As seen from the result, middleware actually doesn’t care whether the response is from a Pages function or is a static resource. Since _headers was inserted before the middleware, I can safely put the headers needed for static resources inside the file, and then build the CSP headers inside the middleware (with my yet-to-be-built Pages Plugin).