Caching static assets at the CDN edge transforms load times from glacial to instantaneous by serving files directly from servers geographically closer to your users.

Let’s see this in action. Imagine a user in London requesting your website, which has its assets hosted on an origin server in New York. Without edge caching, that request has to travel all the way to New York, fetch the HTML, CSS, JavaScript, and image files, and then travel all the way back to London. Each request incurs network latency.

With a Content Delivery Network (CDN) and edge caching enabled for static assets (like .jpg, .png, .css, .js, .woff2), the process changes dramatically. When that London user’s browser first requests your site, the CDN’s edge server closest to London (perhaps one in Amsterdam or Paris) will fetch these static assets from your origin server in New York. Crucially, the CDN then caches these assets on its edge server.

The next time that same London user (or any user near that same CDN edge server) requests your website, the CDN edge server can serve the cached static assets directly from its local storage. The round trip to New York is completely avoided for these files. This means the files arrive at the user’s browser with only the latency of the local CDN edge server, which is orders of magnitude faster.

Here’s a typical Nginx configuration snippet for caching static assets at the edge. This is usually configured within your CDN provider’s dashboard, but the underlying principles are what web servers like Nginx use.

location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2)$ {
    expires 365d;
    add_header Cache-Control "public, max-age=31536000, immutable";
    access_log off;
    log_not_found off;
    tcp_nodelay off;
    tcp_nopush on;
    # CDN-specific headers might be added here, e.g., for Purge API
}

Let’s break down the key components:

  • location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2)$: This is a regular expression that matches requests for common static file extensions. The ~* makes it case-insensitive.
  • expires 365d;: This directive tells the browser (and intermediate caches) how long they can consider the asset "fresh" before needing to revalidate. 365d means 365 days.
  • add_header Cache-Control "public, max-age=31536000, immutable";: This is the more powerful HTTP header that instructs caches.
    • public: Allows the response to be cached by any cache (browser, proxy, CDN).
    • max-age=31536000: Specifies the duration in seconds for which the response is considered fresh. 31536000 seconds is exactly one year.
    • immutable: This is a powerful directive that tells the cache (and browser) that the asset will never change. This allows the browser to skip conditional requests (If-None-Match, If-Modified-Since) entirely, leading to even faster loads on subsequent visits. You can only use immutable if you are certain the file content will not change for the duration specified by max-age, which is typically true for versioned or hashed static assets.
  • access_log off; and log_not_found off;: These reduce the load on the server by not logging requests for these static files, which are usually very frequent.
  • tcp_nodelay off; and tcp_nopush on;: These are TCP tuning parameters. tcp_nopush (or TCP_CORK in Linux) attempts to send all data in a single packet, reducing overhead and latency, especially for small static files. tcp_nodelay off ensures that the Nginx sendfile system call can send data more efficiently.

The problem this solves is the bottleneck of delivering static content. For dynamic content, you need to hit your origin server every time. But for static assets, the content is the same for every user. Why make everyone travel to the same distant origin server? A CDN with edge caching brings that content physically closer to the user, drastically reducing latency. The goal is to make the origin server almost irrelevant for serving these files.

The real magic of immutable in Cache-Control is how it interacts with browser behavior. When a browser encounters immutable, it will not even send a conditional request to the server or CDN for that resource until its max-age expires. For assets that are versioned with a hash (e.g., app.a1b2c3d4.js), the filename changes when the content changes. This means the immutable directive can be safely applied because app.a1b2c3d4.js will never change its content. If you were to change the content of app.a1b2c3d4.js and serve it under the same URL, the browser would still serve the old version from its cache due to immutable, breaking your site. This is why versioning is critical for using immutable effectively.

Understanding how to manage cache invalidation is the next critical step, especially when you do need to update an asset before its max-age expires.

Want structured learning?

Take the full Cdn course →