惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
C
Comments on: Blog
博客园 - Franky
J
Java Code Geeks
D
DataBreaches.Net
G
GRAHAM CLULEY
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Forbes - Security
Forbes - Security
I
InfoQ
Google Online Security Blog
Google Online Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Palo Alto Networks Blog
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
Help Net Security
Help Net Security
P
Privacy International News Feed
量子位
C
Check Point Blog
S
Security Archives - TechRepublic
Stack Overflow Blog
Stack Overflow Blog
AI
AI
云风的 BLOG
云风的 BLOG
Webroot Blog
Webroot Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 聂微东
H
Hackread – Cybersecurity News, Data Breaches, AI and More
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
W
WeLiveSecurity
Know Your Adversary
Know Your Adversary
MongoDB | Blog
MongoDB | Blog
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
H
Help Net Security
C
CERT Recently Published Vulnerability Notes
A
Arctic Wolf
V
V2EX
T
The Blog of Author Tim Ferriss
Cyberwarzone
Cyberwarzone
Microsoft Security Blog
Microsoft Security Blog
AWS News Blog
AWS News Blog
Martin Fowler
Martin Fowler
U
Unit 42
C
Cybersecurity and Infrastructure Security Agency CISA
The GitHub Blog
The GitHub Blog
博客园 - 【当耐特】
美团技术团队

Adactio: Links

The Field Guide to CSS Grid Lanes Happy Monday everyone, and let's talk about gender and ethnicity ratios at tech events. AI and the Rise of Mediocrity The value is in the difficulty - Annotated Tito as Gaeilge Three things about data Native Apps Should Be Avoided Whenever Possible — No One's Happy WebKit Features for Safari 26.5 I knew my writing students were using AI. Their confessions led to a powerful teaching moment | Micah Nathan Google’s Prompt API The Boring Internet Reminder: You Can Stitch Together Lots of Little HTML Pages With Navigations For Interactions Netizen | Derek Sivers Anti-work Let’s Use the Nonexistent ::nth-letter Selector Now | CSS-Tricks Two Paradigms for Enhancing HTML Tags It's Not AI. It's FOMOnetization. The end of responsive images Alistair Davidson / validation-enhancer · GitLab Never Lose Form Progress Again :: Aaron Gustafson Expansion artifacts No-stack web development Design and Engineering, As One Conference organising in 2026 AI Might Be Our Best Shot At Taking Back The Open Web | Techdirt The AI Great Leap Forward they told me the internet was forever Web Day Out - 12 March 2026 Bruce Lawson's personal site Progressive Web Components What we think is a decline in literacy is a design problem | Aeon Essays The End : Focal Curve Flood fill vs. the magic circle Web of State of the Browser Day Out SXSW 02006 Working with agents doesn't feel like flow — Bill de hÓra HTML Video Poster Image: Enable Responsive Images and ALT Text for Poster
Better Browser Caching with No-Vary-Search
Harry Roberts · 2026-05-08 · via Adactio: Links

(last updated on )

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. The Problem We’re Solving
  2. What No-Vary-Search Does
  3. A Simple Example
  4. No-Vary-Search Syntaxes
    1. Ignore Specific Parameters
    2. Ignore All Parameters
    3. Ignore Everything Except Certain Parameters
    4. Ignore Parameter Order
    5. Combining No-Vary-Search Rules
  5. A Small Syntax Gotcha
  6. A Small Debugging Gotcha
  7. Unknown Params Should Bust the Cache
  8. Use It Carefully
  9. A Nice Fit for Messy Real-World URLs

I’ve written, spoken, and generally gone on at length about caching for years now, but a newer addition to the conversation is No-Vary-Search: an HTTP response header that helps us solve a surprisingly common problem with cache keys in HTTP cache (or browser cache).

The short version is, URLs that are materially the same often fail to reuse the same cached response simply because their query strings differ. Sometimes that difference matters to the content and, therefore, the end user. For example:

  • ?colour=red
  • ?colour=blue

And sometimes, it really doesn’t matter at all:

  • ?utm_source=google
  • ?utm_source=chatgpt

The former are very likely different pages, or at least pages that ought to produce different content. We would not want them cached under the same key.

The latter should, in almost every sane setup, return the exact same HTML. They are the same page, just with different tracking baggage attached.

And yet, to an HTTP cache, different query strings traditionally equate to completely different URLs, which means different cache entries. That is wasteful.

Need Some Help?

I help companies find and fix site-speed issues. Performance audits, training, consultancy, and more.

The Problem We’re Solving

By default, caches are cautious. If the URL differs, the cache key differs, and, in a cautious world, that is usually the right thing to do.

This is why:

  • /products/shoes?colour=red
  • /products/shoes?colour=blue

…should remain distinct. The query parameter materially changes the content of the page.

But this also means the cache will usually treat these as distinct pages, too—even if all three return byte-for-byte identical HTML.

  • /sale?utm_source=google
  • /sale?utm_source=chatgpt
  • /sale?utm_source=newsletter

At best, that means wasted cache space; at worst, it means unnecessary trips across the network because the browser cannot reuse a perfectly good response that it already has stored.

This is exactly what No-Vary-Search addresses.

What No-Vary-Search Does

No-Vary-Search is a response header that tells the cache how to treat query parameters when matching a URL to an existing cache entry.

In other words, it lets the server say, via a header, these search parameters do not meaningfully change the response, so do not let them fragment the cache.

This is a little reminiscent of the well known Vary header, but aimed squarely at URL search parameters rather than request headers.

That distinction matters. Vary says this response depends on Accept-Language or this response depends on Accept-Encoding, for example. No-Vary-Search says this response does not depend on utm_source or the order of these parameters should not matter, and so on.

If you know that certain parameters are irrelevant to the response body, you can tell the cache to ignore them, effectively allow- or blocklisting them for cache key purposes.

A Simple Example

Imagine a landing page that is heavily used in campaigns, ads, email, and social posts:

  • /offer?utm_source=google
  • /offer?utm_source=chatgpt
  • /offer?utm_source=linkedin

If those all return the same page, you can tell the cache to ignore utm_source:

No-Vary-Search: params=("utm_source")

Now, as far as cache matching is concerned, those URLs may all reuse the same stored response. They will no longer be treated as separate cache entries just because of the different utm_source values. Much more effective reuse of cached content.

That is the crucial thing to understand: No-Vary-Search is not changing the URL, and it is not rewriting requests. It is changing how cache matching treats the differing query string.

No-Vary-Search Syntaxes

The header has a few useful, different forms.

Ignore Specific Parameters

This is the form I suspect most people will use most often:

No-Vary-Search: params=("utm_source" "utm_medium" "utm_campaign" "fbclid" "gclid")

This says: if the only differences between two URLs are those parameters, treat them as the same cache key.

This is ideal for analytics and campaign tagging, where the query string is useful to you but should not change the response for the user. These standard tracking and social parameters could probably be safely applied to most, if not all, sites.

Ignore All Parameters

If your page genuinely does not vary by query string at all, you can be much broader:

A quick update: the params boolean syntax shown below is likely to change in the spec to an empty list, params=(), instead. At the time of writing, this newer syntax is not yet implemented in browsers, so the original params form remains what you’re most likely to encounter in practice. Thanks to Barry Pollard for the heads-up. Keep an eye on the HTTPWG discussion and the Chromium issue for progress.

That is the boolean form of params, and it tells the cache to ignore all search parameters for matching purposes. This works perfectly for my site which has zero back end, and thus cannot possibly vary by query string.

This is obviously powerful, but also the easiest way to shoot yourself in the foot, so only use it if you really mean it.

Ignore Everything Except Certain Parameters

Sometimes the inverse is easier to express. Perhaps most parameters are irrelevant, but a small number genuinely change the response:

No-Vary-Search: params, except=("colour" "size")

This says: ignore all query parameters except colour and size.

That would be a decent fit for a page where:

  • utm_* tags do not matter,
  • client-side sorting/filtering or tracking parameters do not matter (remember, the HTML itself doesn’t change) but,
  • product variants (?colour, ?size) do.

In that world:

  • /products/shoes?utm_source=google&colour=red
  • /products/shoes?utm_source=chatgpt&colour=red
  • /products/shoes?colour=red&sort=price

could share a cache entry, but:

  • /products/shoes?colour=red
  • /products/shoes?colour=blue

should not.

Ignore Parameter Order

Sometimes the parameters themselves matter, but their order does not:

  • /search?q=shoes&sort=price
  • /search?sort=price&q=shoes

These should usually be treated as equivalent. For that, there is key-order:

No-Vary-Search: key-order

That tells the cache not to create separate entries just because the same parameters arrived, only in a different order.

Combining No-Vary-Search Rules

You can combine directives:

No-Vary-Search: key-order, params, except=("colour" "size")

That tells the cache:

  • parameter order does not matter, and
  • all parameters may be ignored except colour and size.

This means the three following URLs could all share a cache entry:

  • /products/shoes?utm_source=google&colour=red
  • /products/shoes?colour=red&sort=price
  • /products/shoes?sort=price&colour=red

That is probably the most expressive form, and in real systems it may prove the most useful. This is phenomenally powerful.

A Small Syntax Gotcha

No-Vary-Search uses Structured Fields syntax, so the parameter lists are space-separated quoted strings:

No-Vary-Search: params=("utm_source" "utm_medium" "gclid")

…not comma-separated values that you may be used to in most other places.

That is a small detail, but one worth being aware of.

A Small Debugging Gotcha

Note that this also creates a slightly unusual debugging scenario. A very common way to force what we assume will be a fresh trip to the server is to throw a random search parameter on the end of the URL. I’m sure we’ve all done something like this before:

  • /?foo
  • /?test
  • /?asdf

Usually, that gives us a different URL and therefore a different cache key. But if the main document is using No-Vary-Search, that assumption may no longer hold. Appending search params may not bypass cache for this document because the cache has explicitly been told those parameters do not matter.

Honestly, I would love DevTools to surface this more clearly. Something like the existing ⚠️ iconography in the Network panel’s title would be really helpful here: not because anything is wrong per se, but because the browser may be doing something surprising unless you know to look for the No-Vary-Search header.

Unknown Params Should Bust the Cache

One of the trickier practical problems with No-Vary-Search is keeping it all in sync. The marketing team may start using a new utm_* parameter, or an ecommerce team may ship a new filter or facet, and unless that change is reflected in the No-Vary-Search header, caching behaviour may well differ from the ideal scenario.

For that reason, the sensible and defensive default is to always let new and unknown parameters vary the cache key. In other words, if you do not yet know whether a parameter is meaningful, treat it as semantic until proven otherwise.

Imagine marketing starts adding new params, e.g.:

  • ?utm_campaign_variant=summer-a
  • ?utm_campaign_variant=summer-b

If those parameters are absent from No-Vary-Search, then yes, you will miss out on some caching opportunities, but that is no slower than the situation we’ve lived with all along. The worst case scenario is just the status quo: separate cache entries for URLs that are materially the same.

On the flip side, imagine the ecommerce team introduces:

  • ?material=leather
  • ?material=canvas

If those parameters are absent from No-Vary-Search, that is by far the safer outcome. We’d much rather let them produce separate cache entries than accidentally fold distinct pages into one.

This is the same basic principle I recently wrote about in When All You Can Do Is All or Nothing, Do Nothing: when the system lacks the context to be precise, the safer fallback is usually the less clever one. In this case, that means allowing unknown parameters to bust cache until someone has explicitly decided they are safe to ignore.

Again, this is not wasteful—it’s just the same behaviour we’ve always had.

Need Some Help?

I help companies find and fix site-speed issues. Performance audits, training, consultancy, and more.

Use It Carefully

This header is only as good as the assumptions behind it: if two URLs really do return meaningfully different content, then they need different cache entries. I’d rather be served the correct page a little more slowly than the wrong page quickly.

This means No-Vary-Search is best suited to parameters that are:

  • purely analytical;
  • purely presentational on the client side, or;
  • otherwise irrelevant to the server-rendered response.

If a parameter affects the HTML, do not ignore it.

It’s also worth noting that, at the time of writing, this is still an experimental feature and support is not yet universal, so I would treat it as a progressive enhancement rather than a foundational part of your caching strategy. That’s exactly what I’ve done with my site for now.

A Nice Fit for Messy Real-World URLs

What I like about No-Vary-Search is that it acknowledges how the web actually works. URLs pick up baggage: marketing tags get appended, tracking parameters are added, client-side state makes its way into the address bar. Two URLs that are materially the same page often arrive looking totally different.

Historically, caches had to treat those as entirely separate keys, but No-Vary-Search gives us a way to be a little more deliberate. If the response is the same, we can say so. And if only certain parameters matter, we can say that, too.

For teams who care about getting more out of the HTTP cache, that is a very welcome addition!


Frequently Asked Questions

What is No-Vary-Search?

No-Vary-Search is an HTTP response header that tells caches which URL search parameters can be ignored when matching requests to cached responses.

What problem does No-Vary-Search solve?

It reduces cache fragmentation caused by irrelevant query parameters such as UTM tags, so materially identical URLs can reuse the same cached response.

When should I use No-Vary-Search?

Use it when some query parameters do not meaningfully change the response body, such as analytics, campaign, or other tracking parameters.

When should I not use No-Vary-Search?

Do not use it for parameters that change the HTML or otherwise alter the response in a meaningful way, such as product variants or content filters rendered on the server.

Can No-Vary-Search ignore all query parameters?

Yes. Today, the `params` form can tell caches to ignore all search parameters, but the spec is moving toward `params=()` instead. In either case, it should only be used when the response truly does not vary by query string.

Does No-Vary-Search affect debugging?

Yes. Appending a throwaway query string to try to bypass cache may no longer work if the document uses No-Vary-Search and the cache has been told those parameters do not matter.