Setting response headers only on documents

Hi, @Nakib, would you please send us the URL where the header isn’t working? If you do so, we’ll be happy to take a look to see what is happening and why.

I have changed the .toml file a little and now it is working for all files except .html files. My site: So please check why it is not working for .html files.

Hey @Nakib,
I believe we answered your above question over here:

As for the *.html files, you will not be able to accomplish what you want today. This comment explains:

We’ve opened a feature request and have added your +1 to it. We’ll definitely update here if there’s any movement on that!

As for the *.html files, you will not be able to accomplish what you want today.

so… are we there yet? :nerd_face:

lighthouse complains about a malformed robots.txt due to preload headers with a /* rule.

Unfortunately not! Though, you may be able to circumvent the error by specifying more specific paths (assuming not all .html files are in your root directory).

then you should allow for _headers templating.

correct me if i’m wrong but, your documentation says you will look in the publish dir for the _headers file, but if i template it, let’s say with jekyll, i get syntax errors, because you are looking in the root dir instead of the processed /site/_headers file.

Not too sure what you’re templating, I’m afraid! Feels a little bit redundant however maybe I’m missing a part of your workflow?

My suggestion was that, in your _headers file, you could have something like:

  [not the /* rule]

[...existing rules]


  [not the /* rule]

[... existing rules]

Depending on your site’s hierarchy :slight_smile: If you’re looking for dynamic header creation, perhaps a build plugin would be more practical, with inspiration from a plugin like this perhaps?

i added a blank line and it seems to be working now…

the root _headers file looks like this:

layout: null
{%- assign urls = site.pages | map: 'url' | sort -%}
{%- for url in urls %}
{%- if url == '/404' -%}{% continue %}{%- endif -%}
  X-Frame-Options: DENY
  X-XSS-Protection: 1; mode=block
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: microphone=(), camera=(), geolocation=(self "")
  Content-Security-Policy: default-src 'self' https: data: wss: blob: 'unsafe-inline'; script-src 'self' https: data: 'unsafe-inline' 'unsafe-eval'; report-uri
  Link: </assets/fonts/inter/Inter-Roman.var.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin=anonymous

{% endfor %}

the build ran successfully

spoke too soon… it’s not working… although the generated /site/_headers seems fine.

and if i take the result of this template and paste it in the root _headers file it works.

Hi @cdeath,

Could you share the repo? As long as the headers file is getting correctly generated in the publish path, it should work fine.

i don’t have permissions for it… sorry…
but i’ll try to replicate this in another repo and invite you later.

This has become a major blocker on the project I’m working on (and a huge headache for our users) and I’m really hoping I’m just missing something obvious.

We have a SPA built using SvelteKit. All pages should have a no-cache header but all assets should not. Without the no-cache header, deploys break. It’s critical.

The problem is, I can’t figure out how to add this header on just the pages and not the assets.

The pages themselves don’t use the .html extension, so an *.html glob is not an option.

Pages deeper in the app, like /about, must also have this no-cache header, so / isn’t an option either.

URLs are dynamic and prerendered, so I can’t set headers manually on every single page in the configuration file.

How can I accomplish this? Any help would be so appreciated.

Hi @greyivy,

The only way at the moment that would work for you is to write a template that would generate the required headers for all the paths. So, your build command would generate the required _headers file.

I don’t have a better answer, but till the time the feature is not implemented, that’s the only workaround apart from manually typing all the paths.

Is there any progress on this?

Hi @okikio,

Unfortunately, no. The only solution is the one before your reply other than manually typing all the values.

I hope netlify implements this feature soon.

Any word on this? IIUC, it is still not possible to set headers specifically and only for requests that do not end in an extension, like .html, or a slash and do not have a common prefix to match against and without adding all (known) individual paths to _headers or netlify.toml.

I want to set a header on requests for “/contact”, “/about”, “/privacy”, etc., but not for “/images/logo.png”, “/favicon.ico”, “/styles/common.css”.

HTML is the only extension that can’t be set headers for. Otherwise, you can do something like /*.[ext] and it works.

For anyone stumbling upon this thread in 2022, we can now fix this issue for ourselves using a Netlify Edge Function!

I wrote a blog post on this approach and included a code snippet that you can grab here:

This should satisfy the webhint Unneeded HTTP Headers (no-html-only-headers) rule. I also added in the x-frame-options header too. Webhint doesn’t mention that one, but for me I don’t mind only applying it to HTML resources. Your mileage may vary, and I’m not a security expert by any means!

1 Like

Thank you for coming back and sharing this-- this will definitely be beneficial to future Forums members who encounter this obstacle.

Happy building :rocket:

1 Like