Grokking Scalable Systems for Interviews
Ask Author
Back to course home

0% completed

Vote For New Content
What Is Negative Caching and When Should You Cache 404 or Empty Results?
On this page

Understanding Negative Caching

How negative caching works step by step

Why is Negative Caching Important?

Examples of Negative Caching in Action

When Should You Cache 404 or Empty Results?

Best Practices and Final Thoughts

Negative caching means caching a failure or “nothing here” result. Instead of only storing successful responses, you also cache certain errors (e.g., 404 Not Found) or empty results (e.g., “no rows”), for a short time. The payoff: you protect your databases and upstreams from repeated, identical misses and failures, slash latency for repeat lookups that would fail anyway, and smooth out incident blast radius.

In simpler terms, it means caching "nothing" or errors on purpose. Instead of only caching successful data (positive caching), the system also caches cases where data was not found or an error occurred.

This prevents the system from redundantly performing the same failing operation over and over, which can save time and resources.

Negative Caching
Negative Caching

Understanding Negative Caching

In normal caching, only successful results (e.g. a fetched web page or a database record) are stored.

Negative caching, by contrast, stores unsuccessful results – for example, a "404 Not Found" HTTP error or an empty result set – and reuses that result for a short time.

The core idea is to avoid repeatedly doing work that is known to fail.

If a request or query has recently failed (no data found, or returned an error), the cache remembers that failure.

Subsequent requests for the same item can then get the cached negative response immediately, instead of hitting the database or server again.

This is especially useful in scenarios where failures happen frequently (e.g. lots of lookups for data that doesn't exist), as it improves system performance by preventing duplicate work.

Why "Negative"?

It's termed negative because you're caching the absence of something (or an error) rather than a normal (positive) piece of data.

For example, caching a 404 error page for a missing file means the cache stores the fact "this file is not found" and can quickly return that same 404 response next time, without bothering the origin server. I am running a few minutes late; my previous meeting is running over.

This guide explains negative caching in plain English, then walks you through the exact request flow, practical TTL policies, common pitfalls, and simple implementation patterns. Two clean diagrams are included so you can drop them into a blog, deck, or PRD.

How negative caching works step by step

  1. Request arrives for key K (e.g., /users/123).

  2. Check cache for either a positive entry or a negative entry.

  3. If negative hit and TTL not expired → return the cached failure immediately.

  4. Otherwise call origin (DB or service).

  5. Classify result

    • Success (2xx / non-empty) → write positive cache; delete any negative entry.
    • Permanent absence (404/410 or “no such key”) → write a negative entry with a short TTL.
    • Rate limited/temporary (429/5xx/timeout) → optionally write a soft negative with even shorter TTL and honor Retry-After if present.
  6. Return response to caller.

  7. On create/update events that make K valid later, actively evict the negative entry (don’t wait for TTL).

  8. On TTL expiry, the next request is allowed to hit origin again; if successful, the negative is replaced by a positive.

Why is Negative Caching Important?

Negative caching can be a significant performance optimization in the right situations. Some key benefits include:

  • Avoiding Redundant Requests: By caching failed outcomes, the system prevents itself from repeatedly processing the same unsuccessful request. For instance, if a user keeps requesting a nonexistent item, the first failure is cached so subsequent requests don’t hit the database or server again. This reduces unnecessary load on your backend.

  • Faster Response on Errors: Users get faster responses for repeated failed requests because the answer ("not found" or error) comes from cache instantly, rather than after a long backend lookup each time. Although the response is an error or empty result, it’s delivered with minimal latency from the cache.

  • Resource and Cost Savings: Caching negative results saves CPU, memory, database, or network resources that would otherwise be wasted on fruitless operations. The system can use those resources for other tasks. In large systems, this also translates to cost savings – fewer database reads, external API calls, or disk operations mean lower utilization and potentially lower cloud bills.

  • Higher Cache Hit Ratios: Surprisingly, caching "nothing found" can improve your cache hit ratio. If you don’t cache empty results, every request for that missing data is a cache miss. Caching the empty result turns those into cache hits, raising the overall efficiency of the cache. Facebook’s cache engine (CacheLib) notes that failing to cache empty query results would lower the cache hit rate significantly, so they employ negative caching for such cases.

  • Better User Experience (in some cases): If an error condition (like a rate limit or "no results") is going to persist for a short while, negative caching can spare the user from waiting through repeated attempts. For example, if an API has told a client "you’ve made too many requests" (HTTP 429) and that state will last 1 minute, the client can cache that error response and avoid hitting the API repeatedly during that minute. The user won’t experience additional slow failures – the application quickly informs them of the limit until it resets.

In summary, negative caching is about efficiency.

It is most beneficial in read-heavy systems or scenarios with frequent lookup failures, where it acts as a safety net against wasteful repetitive work.

By remembering failures, the system operates smarter, not harder.

Examples of Negative Caching in Action

Negative caching is used in various contexts in software engineering, from low-level networking to high-level web apps.

Here are some common examples and scenarios:

  • DNS Lookup Failures: The Domain Name System (DNS) heavily uses negative caching. When you look up a domain name that doesn’t exist, DNS resolvers cache that negative answer (called an NXDOMAIN) for a short time. This means if the same nonexistent domain is queried again, the resolver responds immediately from its cache, instead of asking the DNS servers again. This reduces unnecessary DNS traffic on the network and speeds up the "domain not found" response. For instance, if bestcode.io is unregistered, a DNS server might cache that fact for, say, 3600 seconds (as suggested by the domain’s SOA record). Negative caching in DNS is crucial for efficiency and to prevent flooding DNS servers with repeat queries for invalid names. (Notably, the negative cache TTL is often kept smaller if a domain might appear soon – e.g., for expired domains the suggested negative-cache TTL can be just 900 seconds to avoid long outages if the domain is reinstated.)

  • HTTP 404 “Not Found” on Web/CDN: Content Delivery Networks (CDNs) and web proxies often implement negative caching for HTTP error statuses. A typical case is caching a 404 Not Found response. Suppose a user requests an image that isn’t on the server – the origin returns a 404. A CDN or reverse proxy can cache that 404 for a short period (say 1–5 minutes). During that time, any other requests for the same missing URL will get the cached 404 answer immediately from the edge cache, without bothering the origin server. This spares the origin from needless work and saves bandwidth. For example, Google Cloud CDN by default caches 404 responses for about 120 seconds (2 minutes). This is configurable with negative caching policies, allowing fine-grained TTLs for different error codes (you might cache 404s for 60s, 410 "Gone" for 120s, etc.). Real-world success: The Onion (a news site) found that enabling caching of 404 pages on their CDN dramatically cut their server load – they saw about a 66% drop in bandwidth and 50% drop in web server load once 404s were cached, due to bots repeatedly hitting old broken links. This freed up a lot of resources, since previously over half of their server time was spent uselessly serving 404s to crawlers.

  • API Errors and Rate Limits: Many APIs use negative caching for error conditions like rate limiting. If a client exceeds a rate limit and gets, say, a 429 Too Many Requests or a 503 Service Unavailable, the system might cache that error response for a brief period. This way, subsequent calls from the client within that window get the cached error instantly, and the service isn’t continually hit when it’s known the requests will be rejected. This technique shields the backend during those error conditions. Similarly, for an external API that returns an error (like "data source down"), an application could cache that failure for a short time to avoid hammering the unstable service repeatedly.

  • Database Queries with No Results: In databases or caching layers, a query that returns no rows can be cached as a "negative result" to avoid hitting the DB again for the same query. This pattern is common in systems design. For example, if your app often searches for a record that doesn’t exist, you can store a placeholder in a fast cache (like Redis or Memcached) indicating "no result found for this query". Future attempts will quickly get "no result" from cache without burdening the database. This is particularly valuable if the query is expensive to run. As noted in research by Facebook, complex queries that yield empty results should be cached – otherwise, you waste a lot of computation for nothing and hurt your cache hit ratio. By caching the empty outcome (with a timeout for safety), the system avoids repeated heavy computations for the same empty result.

  • Web Application Missing Data: Outside of HTTP status codes, even at the application level you might cache the fact that something is missing. For instance, a service might cache a “user not found” result so that it doesn’t repeatedly call downstream services for the same non-existent user. Large-scale web apps and microservices use this to prevent thundering herds of requests for an ID that isn’t in the database. The principle remains: if a certain lookup (for a product, user, post, etc.) consistently fails, a short-term cache of that failure can improve response time and reduce backend load.

When Should You Cache 404 or Empty Results?

Negative caching is powerful, but it should be used judiciously. Caching 404 errors or empty results makes sense only in certain situations:

  • When you expect repeated requests for the same missing item: If an item is missing and multiple clients or users keep requesting it, caching the "not found" response is beneficial. A great example is a popular URL that was removed – instead of hitting your server every time, the first 404 can be cached and all subsequent users get the cached 404 until it expires. This scenario often occurs with bots or crawlers repeatedly accessing invalid URLs, or users retrying a search. In such cases, caching the 404/empty result significantly cuts down redundant traffic (as seen with The Onion’s case).

  • When the missing data is unlikely to appear immediately: If you know that a 404 is truly a missing resource (e.g., a deleted page) or an empty query means "no data exists" (not just temporarily empty), then a negative cache with a reasonable TTL is safe. For instance, a product ID that doesn’t exist in your database likely won’t magically appear in the next few seconds. Caching that miss for a short period (say a minute) will not harm consistency but will save a lot of overhead. Stability of content is key: as one expert noted, if your content "doesn't change much," caching 404s can help a lot. If it’s truly an old or permanent 404, feel free to cache it (some systems even cache such errors for several minutes or more by default).

  • When failures are expensive to compute: Use negative caching if a failure results from an expensive operation. For example, an empty result that came from a complex database query or an extensive search should be cached briefly. This ensures that if the same query comes again, the system can return the cached "no results" quickly rather than re-running the heavy query. The costlier the operation to find out something doesn’t exist, the more you gain by caching that outcome.

  • High traffic scenarios and rate limiting: If your system (or an upstream service) is under high load and returning errors (like 503 Service Unavailable or rate limit errors), negative caching those responses for a short time can actually act as a throttle. It prevents flooding the service with identical failing requests. For example, caching a 503 for even 30 seconds can stop thousands of clients from continuously retrying during an outage window. (Some HTTP clients even do this automatically with retry-after headers or similar cues.)

However, there are also times you should NOT cache 404/empty results, or do so with great caution:

  • When the data is highly dynamic: If new content can appear at any moment, caching a "not found" might lead to serving stale errors. For instance, in a fast-changing API where a resource might be added soon, you wouldn't want clients to use a cached 404 – they should check the origin again so they don't miss the newly added data. As a rule of thumb, if an item could exist in the near future, keep the negative TTL very short or avoid caching it. In other words, negative caching can harm correctness if the “not found” condition is transient.

  • If the error is due to a temporary outage or glitch: Don’t cache transient errors like network timeouts, 500 Internal Server Errors, or other temporary failures. Those should be retried, not cached (except perhaps for a few seconds) because the problem might be resolved on the next attempt. Negative caching is best for consistent negative results (like truly nonexistent data), not one-off transient errors.

  • Always use reasonable TTLs: When you do cache a 404 or empty result, configure a short Time-To-Live. This is a best practice emphasized by many experts. Caching negative results “sparingly (e.g., 404s) with very short TTLs” is recommended – for example, on the order of seconds or a few minutes, depending on how quickly things could change. Short TTLs ensure that if the situation changes (the data appears, the page is created, etc.), the negative cache will expire soon and clients will get fresh results. For instance, DNS negative caches often use a small TTL (like 5 minutes or less) for domains that might be registered or updated soon, and CDNs default to a couple minutes for 404s unless configured otherwise. Always balance the performance gain with the risk of staleness.

  • Provide ways to invalidate if necessary: In scenarios where you implement negative caching in your application, consider how to force refresh if needed. For example, if an admin knows a previously missing item has just been added, you might purge the negative cache for that key so users aren’t stuck seeing "not found." While standard HTTP caches will naturally drop the entry after the TTL, in a custom cache you should make sure negative entries don’t stick around too long or can be evicted manually.

In summary, cache 404s/empty results when it prevents a flood of repeated misses or heavy computations, but skip it or keep it brief when new data could arrive at any time. It’s a trade-off between performance and freshness.

Always tailor the caching strategy to the nature of your data and usage patterns.

A stable dataset with lots of invalid lookups is a great candidate for negative caching, whereas a rapidly changing dataset is not.

Best Practices and Final Thoughts

For engineers (especially those prepping for system design interviews or building scalable systems), it’s important to understand negative caching as an optimization tool.

Here are some best practices to keep in mind:

  • Use Negative Caching Deliberately: Don’t just cache errors by accident – plan for it. Identify which failure cases are common and costly in your system (e.g. cache misses for non-existent keys, or 404s due to link rot) and apply negative caching there. Make sure your caching layer or library supports it (many frameworks allow it, sometimes under specific settings).

  • Tune the TTL per Scenario: Not all "not found" should be treated equal. For example, cache a 404 from a static file server longer (maybe a few minutes) because if a file is missing, it likely won’t appear soon. But cache a 404 from a user data API very briefly (few seconds) because a user record could be added any time. As noted earlier, some HTTP caches let you set different TTLs for different status codes – use that flexibility to your advantage.

  • Monitor and Adjust: Keep an eye on your negative cache hits and misses. If you see a high rate of negative cache hits, that means the caching is actively reducing load (good), but also watch that you’re not caching things too long. Monitor if users eventually get a success after a cached failure (which would indicate the cache maybe held a 404 too long). Adjust TTLs based on real-world patterns.

  • Document the Behavior: Negative caching can sometimes confuse developers or ops teams because it’s less common than standard caching. Document which scenarios produce cached negatives and how to clear them if needed. This avoids the “stale error” surprise where everything was fixed but the system is still returning an old 404 from cache. As one source pointed out, if you cache failures, ensure there’s a clear way to know that and to purge the cache when appropriate. Communication is key, so it doesn’t become a hidden anti-pattern.

  • Balance Freshness vs Performance: Ultimately, caching (positive or negative) is about balancing speed with data freshness. Negative caching tilts towards speed/efficiency on failures, but you must always consider the window of time you’re willing to serve a possibly outdated failure. Strive for that balance where users don’t repeatedly trigger expensive failures, yet new content or fixes propagate quickly once available.

By following these practices, negative caching will be a robust tool in your optimization toolkit rather than a pitfall.

When used in the right context – like preventing floods of repetitive 404 requests or expensive empty database lookups – it dramatically improves scalability and response times.

Just remember the golden rule of caching: cache invalidation is one of the hardest problems. This applies to negative caching too – invalidating or expiring those "nothing here" responses at the right time is crucial.

Mark as Completed

On this page

Understanding Negative Caching

How negative caching works step by step

Why is Negative Caching Important?

Examples of Negative Caching in Action

When Should You Cache 404 or Empty Results?

Best Practices and Final Thoughts