Skip to main content

Smarter Website Caching With No-Vary-Search

· 8 min read
Jakub Andrzejewski

Modern websites rely heavily on query parameters that are used for tracking (utm_source), filtering (?size=small), pagination (?page=3), sorting (?sort=quantity), feature flags, search state, and countless other use cases.

However, this means websites can miss out on the performance benefits of HTTP caching. Even if two URLs return identical content, caches generally store them as separate entries simply because the query string differs. That leads to fragmented caches, lower cache hit rates, and unnecessary origin requests from Content Delivery Network (CDN) caches.

The new No-Vary-Search HTTP response header aims to solve this problem by giving browsers and CDNs more control over how query parameters affect cache keys.

In this article, we'll look at:

  • why query parameters are problematic for caching,
  • how No-Vary-Search works,
  • what problems it solves,
  • advanced edge cases,
  • and when you should avoid using it.

The Problem with Query Parameter Caching

Traditionally, caches treat the full URL as the cache key, which means these URLs are considered completely different resources:

/products
/products?utm_source=twitter
/products?ref=homepage

Even if the response body is identical, most caches will create separate cache entries for every variation, and this creates several problems:

  1. Lower Cache Hit Rates: A CDN may already have /products cached, but a request for /products?utm_campaign=spring-sale can still result in a cache miss. At scale, this significantly reduces cache efficiency.
  2. Increased Origin Traffic: More cache misses mean more requests hitting the origin server. For high-traffic applications, especially content-heavy sites, this increases infrastructure costs and backend load.
  3. Browser Cache Inefficiency: The same issue exists in browsers. A browser may already have a page cached, but a slightly different query parameter combination prevents cache reuse.
  4. Overly Complex Cache Rules: Many teams try to work around this problem manually by rewriting URLs, maintaining allowlists, stripping tracking parameters at the CDN layer, or configuring custom cache key normalization logic. These solutions are often vendor-specific and difficult to maintain consistently across platforms.

This is where the new No-Vary-Search HTTP header comes into play.

No-Vary-Search is a new HTTP response header that tells caches which query parameters should, or should not, affect cache matching. Instead of treating every query parameter as significant, servers can explicitly define which parameters matter, for example:

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

This indicates that the utm_source and utm_campaign parameters should be ignored when matching cache entries.

info

Keep in mind that the syntax is strings separated by a space, not a comma.

As a result, all of these URLs can reuse the same cached response:

/products
/products?utm_source=twitter
/products?utm_campaign=winter

The content is treated as equivalent for caching purposes. The header is part of ongoing work to improve cache efficiency and reduce unnecessary cache fragmentation on the modern web.

More Complex Use Cases

Real-world query parameter behavior is rarely simple: the position of query parameters may or may not matter, and different parameters may need different rules. No-Vary-Search supports more advanced patterns for handling these cases.

Ignoring Everything

When a page does not vary by query string, we could set the header value to the following:

No-Vary-Search: params
// or
No-Vary-Search: params=()

Keep in mind that this feature is still experimental. That is why there are two versions, params and params=(). Check this http-extensions pull request and this Chromium issue as pinpointed by Barry Pollard and Harry Roberts.

Ignore parameter order

If a page returns the same content regardless of parameter order, we still want to serve it from one cache entry instead of caching each ordering as a different URL.

For example, the following URL:

/shoes?size=small&sort=price

Should be cached as the same page as:

/shoes?sort=price&size=small

To achieve that, we can set the header to:

No-Vary-Search: key-order

And it will return the same page from cache for these two seemingly identical URLs.

Ignore everything except X, Y

Sometimes it is better to set the rule to ignore everything but have an exception for just a few query parameters and it can be done like the following:

No-Vary-Search: params, except=("variant" "price")
tip

Remember the syntax: rules are listed after a comma, while parameters are in quotation marks and separated by spaces.

Combining multiple rules

We may have a scenario where we need to use multiple rules at the same time and it can be done like this:

No-Vary-Search: params, key-order, except=("variant" "price")

This rule will instruct the cache that all parameters may be ignored, the order of query parameters does not matter, and to not ignore the variant and price parameters.

This way, all the following URLs will be cached under the same entry:

/products/shoes?variant=compact&size=small
/products/shoes?size=small&variant=compact
/products/shoes?utm_source=google&variant=compact

Combining the rules like this gives you fine-grained control over exactly which URLs share a single cache entry.

No-Vary-Search is powerful, but using it incorrectly can cause serious caching bugs.

The rule is simple: never ignore query parameters that change the response content.

But to be more precise, you should not use it in the following examples:

  • Personalized Content: Avoid using it for parameters related to authentication, session state, localization, experiments, or personalization. For example /dashboard?user=peter must never share cache entries across users.
  • Search Queries: Page /search?q=laptop is different from /search?q=monitor and that is why we shouldn't be ignoring the q query param as it would break the application.
  • Pagination: Pagination parameters are also content-defining. Page ?page=1 is different from ?page=2. These must remain distinct cache entries.
  • Unclear Cache Behavior: If you're unsure whether a parameter affects content, it's safer not to ignore it. Incorrect cache reuse can lead to users seeing stale content, broken personalization, or even security issues.

Keeping in mind these scenarios will help you avoid common caching problems.

tip

This only matters if the query parameters are used by the backend server to render the HTML. If your client-side code is responsible for handling a q search parameter for example then it's fine to use No-Vary-Search for that parameter.

No-Vary-Search and speculation rules

Speculation Rules let web developers ask the browser to speculatively pre-render future pages a visitor is likely to visit. When the user actually navigates to the next page, this navigation can be practically instant.

However, you might have links to /login, /login?source=sidebar and /login?source=footer. If just the plain /login is pre-rendered the other two links won't result in an instant navigation. Using No-Vary-Search for the source parameter fixes this issue.

But what if you're pre-rendering the /login page but then click on /login?source=sidebar before the request is complete? The browser won't know about No-Vary-Search until the response is received.

To work around this problem, speculation rules offer the expects_no_vary_search option. The browser can then wait for the existing pre-render request instead of starting a new navigation.

<script type="speculationrules">
{
"prerender": [{
"source": "list",
"urls": ["/login"],
"expects_no_vary_search": "params=(\"source\")"
}]
}
</script>

Browser compatibility

The feature is currently marked as Experimental which can change in the future. Below is a small browser compatibility matrix that shows where this feature is currently supported.

FeatureChromeFirefoxOperaSafariEdge
No-Vary-Search (Experimental)YesNoYesNoYes

For full browser compatibility, check out the MDN No-Vary-Search reference.

Summary

Query parameters have always been one of the messiest parts of HTTP caching. Most sites depend on them heavily, but traditional cache behavior treats every variation as a separate resource, even when the response is identical.

No-Vary-Search introduces a cleaner and more standardized way to handle this problem. By explicitly defining which query parameters matter for cache matching, websites can:

  • improve cache hit rates,
  • reduce origin traffic,
  • simplify cache configuration,
  • and improve browser cache reuse.

For content-heavy websites with lots of tracking parameters, the performance impact can be significant. At the same time, the header must be used carefully. Ignoring the wrong parameters can easily introduce broken or unsafe cache behavior.

Like many caching optimizations, the mechanism itself is the easy part. The real work is correctly understanding which parts of a URL define the response.

Measure the impact of your performance work

DebugBear lets you monitor the performance of your website and identify high-impact optimizations. Get alerted to performance regressions and see how better performance leads to better business outcomes.

Sign up for a free trial and start monitoring your website today! Run scheduled synthetic tests, benchmark Google CrUX data, and measure real user experience all in one place.

Website monitoring dashboard

Illustration of website monitoringIllustration of website monitoring

Monitor Page Speed & Core Web Vitals

DebugBear monitoring includes:

  • In-depth Page Speed Reports
  • Automated Recommendations
  • Real User Analytics Data

Get a monthly email with page speed tips