Skip to main content
DevOps7 min readMarch 3, 2026

CDN Configuration: Making Your Static Assets Load Instantly Everywhere

Configure a CDN correctly for maximum performance — cache control headers, invalidation strategies, origin pull optimization, and serving static assets at global edge.

James Ross Jr.

James Ross Jr.

Strategic Systems Architect & Enterprise Software Developer

CDN Configuration: Making Your Static Assets Load Instantly Everywhere

A CDN configured correctly is one of the highest-leverage performance improvements you can make to a web application. A CDN configured incorrectly gives you false confidence while doing almost nothing. I have seen production applications with Cloudflare in front that were caching nothing because every response included a Cache-Control: no-store header added by a framework default that nobody questioned.

Let me walk through how I think about CDN configuration and the specific settings that matter.

What a CDN Actually Does

A CDN is a distributed network of servers placed geographically close to users. When a user in Paris requests your JavaScript bundle, they hit a CDN edge node in Paris instead of your origin server in Virginia. The round-trip time drops from 150ms to 5ms for the static asset.

The key word is "static." A CDN excels at serving content that does not change between requests: JavaScript bundles, CSS files, images, fonts, videos. CDNs can also cache dynamic content — API responses, server-rendered HTML — but this requires more careful configuration because you need to account for when that content changes.

The CDN stores a cached copy of the response at the edge. Subsequent requests for the same resource are served from the cache without touching your origin server. This reduces origin load, reduces latency for users, and provides resilience if your origin has a temporary issue.

Cache-Control Headers: The Foundation

Your cache behavior is primarily determined by the Cache-Control header your origin server sends. The CDN respects these headers and caches accordingly.

For static assets with content-addressed filenames (the standard for JavaScript bundles and CSS files built by Webpack, Vite, or esbuild), you can cache aggressively:

Cache-Control: public, max-age=31536000, immutable

public allows CDN and browser caching. max-age=31536000 is one year in seconds. immutable tells the browser not to bother revalidating during the max-age period — the content never changes because the URL changes when the content changes. This combination gives maximum caching efficiency.

For HTML pages, you typically want shorter caching or no caching, since HTML references your JavaScript and CSS files by their content-addressed URLs:

Cache-Control: public, max-age=0, must-revalidate

This allows CDN caching but requires revalidation on every request. The CDN sends an If-None-Match or If-Modified-Since request to your origin. If the content has not changed, the origin returns a 304 with no body — cheap to process — and the CDN serves its cached copy. If it has changed, the origin returns the new content.

For authenticated or user-specific content:

Cache-Control: private, no-cache

private prevents CDN caching. no-cache allows browser caching but requires revalidation. This is appropriate for responses containing user-specific data that should not be shared across users via a CDN cache.

Cloudflare Configuration

Cloudflare is my default CDN recommendation because it combines CDN functionality with DNS, DDoS protection, and a comprehensive security layer. Here is how I configure it for a typical application.

In your Cloudflare dashboard, set the caching level to "Standard" under Caching > Configuration. This respects your Cache-Control headers. The "Aggressive" mode overrides some headers, which creates confusion.

Create Cache Rules (Caching > Cache Rules) to ensure your build assets are cached at the edge:

Rule: Cache static assets
When: Request URI path matches regex \.(js|css|woff2|woff|ttf|svg|png|jpg|webp|ico)$
Then: Cache eligibility = Eligible for cache
      Edge Cache TTL = 1 year
      Browser Cache TTL = Respect existing headers

Create a separate rule for your HTML files:

Rule: HTML - short cache
When: Request URI path matches regex \.html$ or Request URI path is /
Then: Cache eligibility = Eligible for cache
      Edge Cache TTL = 5 minutes
      Browser Cache TTL = Respect existing headers

Enable "Always Use HTTPS" to redirect HTTP to HTTPS at the Cloudflare edge, before requests reach your origin. Enable "Automatic HTTPS Rewrites" to fix mixed content issues by rewriting http:// references in HTML to https://.

Cache Invalidation

The two hard things in computer science are cache invalidation and naming things. Here is how to handle the CDN invalidation problem cleanly.

For JavaScript bundles, CSS, and images: use content-addressed filenames. Vite, webpack, and esbuild generate filenames with hash suffixes like app.a3f8b2c.js. When the content changes, the hash changes, the URL changes, and the cache miss is automatic. Old files stay cached (harmless, nobody requests them anymore) and new files are always fresh. Zero explicit invalidation required.

For HTML and API responses: they change based on application state, not file content. Here you need explicit invalidation. When you deploy, immediately purge your HTML cache:

# Cloudflare cache purge via API
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything":true}'

A targeted purge by URL is preferred over purging everything, but "purge everything" is safe for a deployment since your asset URLs have changed anyway.

Automate this in your CI/CD pipeline. Your deploy job should trigger cache purge after a successful deployment:

- name: Purge Cloudflare cache
  run: |
    curl -X POST \
      "https://api.cloudflare.com/client/v4/zones/${{ secrets.CF_ZONE_ID }}/purge_cache" \
      -H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
      -H "Content-Type: application/json" \
      --data '{"purge_everything":true}'

Vary Headers and Cache Segmentation

The Vary header tells the CDN that the same URL can return different responses based on specific request headers. A common example is Vary: Accept-Encoding — compressed and uncompressed responses are cached separately.

Most CDNs handle Vary: Accept-Encoding automatically and serve Brotli or gzip compressed responses to clients that support them. Enable Brotli compression in Cloudflare under Speed > Optimization.

Be careful with Vary: Cookie or Vary: Authorization. These headers cause the CDN to cache a separate copy for every unique cookie or authorization value — effectively bypassing caching entirely for authenticated content. If you need different responses for authenticated vs. unauthenticated users, use different URLs or cache only the unauthenticated version.

Origin Shield

For high-traffic applications, consider enabling Cloudflare Argo (or an equivalent origin shield feature). Origin shield adds a second cache layer between edge nodes and your origin. When multiple edge nodes get a cache miss for the same resource, only one request hits your origin — the others queue and receive the response from the first. This dramatically reduces origin load during traffic spikes.

The cost is worth it for origins that are expensive to serve from: application servers rendering server-side HTML, APIs hitting databases, or any origin where you pay per request.

Debugging Cache Behavior

Cloudflare adds a CF-Cache-Status response header that tells you whether a response was served from cache:

  • HIT — served from edge cache
  • MISS — not in cache, fetched from origin
  • EXPIRED — was in cache but expired, refetched from origin
  • BYPASS — cache bypassed due to cache rules or Cache-Control: no-store

Use your browser's network panel to check this header on every resource type. If you expect something to be cached and it shows MISS on repeated requests, your cache headers are incorrect. If it shows BYPASS, your cache rules need adjustment.

The Cloudflare cache inspector tool under Caching > Cache Rules > Test shows you exactly which rules would apply to a given URL and what the cache behavior would be.

The Assets Worth Prioritizing

Not all assets have equal impact. Focus your CDN optimization effort on the assets that block rendering: JavaScript bundles, CSS files, web fonts. These are the resources that directly affect Time to Interactive and Largest Contentful Paint.

Images matter for perceived performance but are less likely to block rendering. Use modern formats (WebP, AVIF) and lazy loading for below-the-fold images. Video should always be served from a CDN or a dedicated video platform — video through your origin server will ruin your infrastructure.

A properly configured CDN with correct cache headers on your build output is one of the fastest paths to meaningfully better Core Web Vitals scores.


If you want help designing a CDN and caching strategy for your application, book a call at https://calendly.com/jamesrossjr.


Keep Reading