Skip to main content

Outline

At a glance:
  • What it is: Cache static assets in the browser or CDN for faster page loads.
  • Why it matters: Reduces latency, server load, and bandwidth usage.
  • Core APIs: UseStaticFiles middleware, Cache-Control headers, asp-append-version.
  • Best practices: Aggressive caching, cache busting, CDN integration, compression.

Introduction

Static file caching stores CSS, JavaScript, images, and fonts closer to the end-user (browser or CDN) to improve performance, reduce server load, and enhance user experience. This module provides a comprehensive overview of static file caching within Optimizely solutions.

1. UseStaticFiles Middleware

The UseStaticFiles middleware is the entry point for configuring how static assets are served and cached. Use StaticFileOptions.OnPrepareResponse to set cache headers on every static file response.

C#
var builder = WebApplication.CreateBuilder(args); // ... other services var app = builder.Build(); // Configure static files with cache headers app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = ctx => { const int durationInSeconds = 60 * 60 * 24 * 30; // 30 days ctx.Context.Response.Headers[HeaderNames.CacheControl] = "public,max-age=" + durationInSeconds; ctx.Context.Response.Headers[HeaderNames.Expires] = DateTime.UtcNow.AddSeconds(durationInSeconds).ToString("R"); } }); app.Run();

Note: UseStaticFiles must be called before UseRouting in the middleware pipeline to ensure static files are served without going through the full routing stack.

2. Cache-Control Headers

The Cache-Control header is the primary mechanism for instructing browsers and CDNs how to cache a response. Understanding the available directives allows precise control over caching behavior.

Cache-Control directives

Select a directive to expand and read when to use it.

public

Indicates the response can be cached by any cache - browsers, proxies, and CDNs. Use for static assets that are not user-specific (CSS, JS, images). Required for CDN edge caching to work.

private

Intended for a single user only. The response can be stored in the browser cache but not in shared caches such as CDNs or proxies. Use for personalized content or user-specific responses.

no-cache

The cached response must be revalidated with the origin server before use. The resource can still be stored, but a round-trip to the server is required on each use. Use when freshness must be confirmed but bandwidth optimization is still desired.

no-store

The response must not be stored in any cache, ever. Use only for sensitive data (authentication tokens, financial responses) where caching would be a security risk. Do not use for static files.

max-age=<seconds>

Defines the time in seconds a resource is considered fresh. Applies to the browser cache. After this period expires, the browser must revalidate. For static files with cache busting, use a long value such as 2592000 (30 days).

s-maxage=<seconds>

Applies specifically to shared caches such as CDNs and proxies, overriding max-age for those layers. Use when you want different TTLs for browser and CDN - for example, shorter at the CDN to allow faster invalidation without affecting browser cache duration.

3. File Versioning (Cache Busting)

Aggressive caching only works safely when you can reliably invalidate cached versions after a deploy. The asp-append-version Tag Helper appends a file-content hash as a query string to each static file URL. When the file changes, the hash changes, and browsers and CDNs treat it as a new resource.

HTML
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" /> <script src="~/js/site.js" asp-append-version="true"></script>

Pro tip: Cache busting via asp-append-version is what makes long max-age values safe. Without it, a 30-day cache means users may see stale CSS or JS for up to 30 days after a deployment. Always pair aggressive caching with reliable cache busting.

4. ETag and Last-Modified Headers

Conditional request headers allow browsers to verify whether a cached resource is still fresh without downloading the full content. The UseStaticFiles middleware handles both headers automatically.

  • ETag: A unique identifier for a specific version of a resource. When a browser revalidates, it sends the stored ETag; if it matches, the server returns a 304 Not Modified response with no body, saving bandwidth.
  • Last-Modified: The date and time the resource was last changed. Used similarly to ETag for revalidation; the server returns 304 if the resource hasn't changed since the date provided.
  • Automatic handling: The UseStaticFiles middleware sets both headers automatically - no additional configuration is required.

5. CDN Integration

A CDN distributes cached copies of static assets to edge nodes around the world, dramatically reducing the distance between end-users and the content they request.

  • Edge caching: CDNs cache assets at geographically distributed nodes, reducing latency for users regardless of their location.
  • Configuration: Set Cache-Control headers including max-age and s-maxage to control CDN-specific TTLs independently of browser cache duration.
  • Cache invalidation: Purge URLs or cache zones when assets update. Combine CDN purging with file versioning so that even CDN-cached assets are replaced immediately after deployment.

6. Optimizely Media Assets

  • Media URL rewriting: Serve images, videos, and documents via middleware or CDN to take advantage of the same caching strategies applied to other static assets.
  • Versioned media URLs: Optimizely appends a version query string to updated media asset URLs automatically, providing built-in cache busting for editor-managed content.

Best Practices

  • Aggressive caching: Use a long max-age (30 or more days) for static files in production.
  • Implement cache busting: Use asp-append-version or manual versioning on all static file references.
  • Leverage a CDN: In production, route static assets through a CDN to ensure global performance and reduce origin server load.
  • Enable compression: Serve static assets with Gzip or Brotli compression to reduce transfer size. Use UseResponseCompression middleware or configure compression at the CDN/server layer.
  • Minification and bundling: Reduce the number of requests and the size of transferred files through build-time minification and asset bundling.
  • Monitor performance: Verify caching behavior using browser developer tools (Network tab, cache status) or performance monitoring services after each deployment.

Important: Always test caching behavior in a staging environment before deploying to production. An incorrectly configured Cache-Control header can cause users to receive stale assets for the full duration of the max-age period with no way to force a refresh.

Conclusion

Static file caching is an indispensable technique for optimizing the performance and scalability of Optimizely CMS 12 and Commerce 14 solutions. By correctly configuring ASP.NET Core's static file middleware, leveraging HTTP caching headers, implementing robust cache busting strategies, and integrating with a CDN, development teams can significantly reduce page load times, decrease server load, and deliver a superior user experience.

Adhering to these best practices ensures that static assets are delivered efficiently, contributing to a high-performing Digital Experience Platform.