Nginx Caching Strategies

February 13, 2026 | Nginx Caching Performance

proxy_cache, invalidation, and hit rates.

Why Nginx Caching Matters

Nginx's reverse proxy cache can dramatically reduce backend load and improve response times. By caching API responses, rendered pages, and static assets at the proxy layer, you can serve 80-90% of requests without hitting your application servers — resulting in faster page loads and lower infrastructure costs.

Basic proxy_cache Configuration

Define a cache zone and apply it to your proxy locations:

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app_cache:10m
                     max_size=1g inactive=60m use_temp_path=off;

    server {
        location /api/ {
            proxy_cache app_cache;
            proxy_cache_valid 200 10m;
            proxy_cache_valid 404 1m;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
            proxy_cache_key "$scheme$request_method$host$request_uri";

            add_header X-Cache-Status $upstream_cache_status;
            proxy_pass http://backend;
        }
    }
}

Cache Configuration Explained

  • levels=1:2 — Two-level directory hierarchy for cache files
  • keys_zone=app_cache:10m — 10MB shared memory zone for cache keys (~80,000 keys)
  • max_size=1g — Maximum disk space for cached content
  • inactive=60m — Remove items not accessed for 60 minutes
  • use_temp_path=off — Write directly to cache directory (avoids unnecessary disk I/O)

Stale Content Serving

The proxy_cache_use_stale directive is critical for reliability. When backends are down or slow, Nginx serves cached content instead of returning errors:

proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;

With proxy_cache_background_update, Nginx serves stale content to the current request while refreshing the cache in the background — users never see stale content or errors.

Cache Bypass and Purging

Allow specific requests to bypass or purge the cache:

# Bypass cache for authenticated users
map $http_cookie $no_cache {
    default 0;
    "~*session_id" 1;
}

server {
    location /api/ {
        proxy_cache app_cache;
        proxy_no_cache $no_cache;
        proxy_cache_bypass $no_cache;
        proxy_pass http://backend;
    }
}

Micro-Caching for Dynamic Content

Even caching dynamic API responses for 1 second can absorb traffic spikes:

proxy_cache_path /var/cache/nginx/micro levels=1:2 keys_zone=micro:5m max_size=500m;

location /api/feed {
    proxy_cache micro;
    proxy_cache_valid 200 1s;
    proxy_cache_lock on;
    proxy_pass http://backend;
}

This "micro-caching" pattern serves all concurrent requests for the same resource from a single backend request — transforming 1,000 concurrent requests into 1 backend hit per second.

Measuring Cache Effectiveness

Monitor the X-Cache-Status header values:

  • HIT — Served from cache (target: >80%)
  • MISS — Fetched from backend and cached
  • EXPIRED — Cache entry expired, refreshed from backend
  • STALE — Served stale content due to backend issues
  • BYPASS — Cache intentionally skipped

Track your cache hit ratio: HIT / (HIT + MISS + EXPIRED). A healthy ratio is above 80% for static content and 50-70% for API responses.

Eazy SaaS Tip: We implement a tiered caching strategy for our clients: Nginx proxy cache for API responses, browser cache headers for static assets, and CDN caching for global distribution. This approach typically reduces backend load by 85% and cuts P95 latency in half.