Format of custom headers glob

In netlify.toml, you can set custom headers like this:

[[headers]]
for = "/*.(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)"

What’s the format for this glob? Will /* match subdirectories? Is it equivalent to this regex ^/.*\.(jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$?

Sadly, the format does not support regexps, only the simple glob. You will need to create one rule per extension.

when you use “/*.jpg” as the target, it will cover every jpg file on your site.

I have a rule with (a|b) on my site. I think it’s working. Is that part of the glob rules?

I’m shocked to hear that and would recommend changing it ASAP for best behavior :slight_smile:

It’s definitely working? Here’s a rule in my netlify.toml:

[[headers]]
for = "/*.(css|ttf|ttc|otf|eot|woff|woff2)"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable" # 1 year

And the output of curl -I for my CSS:

HTTP/2 200
accept-ranges: bytes
content-length: 66555
content-type: text/css; charset=UTF-8
date: Tue, 28 Apr 2020 14:24:32 GMT
etag: "3b33c3acedf8c2e98f4f5907cec086c6-ssl"
strict-transport-security: max-age=31536000
age: 0
server: Netlify
cache-control: public,max-age=31536000,immutable
x-nf-request-id: 8cd9eb23-8765-473d-b4eb-11f0a8bd611c-7325384

The Netlify CDN can’t have just coincidentally decided to add cache-control immutable, so the glob must be doing something…

Glad that format is working for you! It may stop working at any time, so if you want our advice, you’ve got it, and I think the peace of mind around changing one rule for 7 is totally worthwhile.

And you’re right - we would never ever add that particular header - our default caching is very carefully considered and your configuration (setting a long cache timeout) is a worst practice for most folks who do it without thinking it through. I guess you’ve probably seen this article, but in case you haven’t:

Not saying you need to change things - you seem pretty thoughtful and I guess you know you’ll not want to change a css file in the next year (though that seems quite suspect to me now that I say it out loud - for a font it makes sense, but really, for css?). I have just have spent so many hours troubleshooting for folks who set a timeout like that, and had to rename all their files to “dodge” their old, bad config - it’s super hard for us to debug since all we know is “that file is changed in our database” - we can’t see past caching headers settings easily.

But anyway, now you know the full story and can make the decisions that match your desired risk level and meet your goals best! :slight_smile:

My CSS file names are hashed, so there should never be a reason to use the same filename with old content.

Okay, good to know that my configuration working was only a coincidence and not by design. That was what I opened this issue to figure out: I’ve had this configuration for a while, but when I was reading the docs I couldn’t figure out why it actually worked. I guess the answer is that Netlify is using some globbing library internally today but might not tomorrow. I’ll change it when I get a chance.

1 Like

Why it is not working in my case. `[[headers]]
for = “/*.js”
[headers.values]
cache-control = “max-age=31536000”

for = "/*.css"
[headers.values]
    cache-control = "max-age=31536000"

for = "/*.woff"
[headers.values]
    cache-control = "max-age=31536000"

for = "/*.png"
[headers.values]
    cache-control = "max-age=31536000"
`

Here only the .js file gets bundled but in the network tab, I see for: “/*.png” on bundle.js header. That means bundle.js is getting the header for “/*png”. Why? And why other are not working?

Edited:

You’re indenting it as though that affects the value. It does not. It’s just there for human readability. The computer ignores it.

You need to add more [[headers]] to separate the entries. Like this:

[[headers]]
for = "/*.css"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable" # 1 year

[[headers]]
for = "/*.gif"
[headers.values]
Cache-Control = "public, max-age=1209600" # 2 weeks
2 Likes

Thanks,` @carlmjohnson Now it works for all files except .html files.

[[headers]]
for = "/*.html"
[headers.values]
    Cache-Control = '''
    public,
    max-age=36000,
    must-revalidate'''

Don’t know why this happens. It happens for all.HTML files including index.html

Thanks so much for jumping in @carlmjohnson :trophy:

@Nakib, we’ve responded to you over here --> Setting response headers only on documents