← Back to Apache Course | Chapter 5: Performance | Lesson 3 of 4

Caching

Caching tells browsers (and any proxies in between) that a file hasn't changed and can be reused, so it doesn't need to be downloaded again on the next visit -- saving bandwidth and making pages feel faster.

Cache-Control and Expires

Cache-Control: max-age=604800 tells the browser it can reuse a file for 7 days without asking the server again. The older Expires header does a similar job with an absolute date instead of a duration. Modern configs mostly use Cache-Control, often alongside Expires for compatibility with very old clients.

mod_expires

mod_expires generates these headers automatically by file type, rather than hand-writing a Header rule for every extension. ExpiresByType image/jpeg "access plus 1 month" tells Apache to add caching headers to every JPEG response automatically, valid for a month from when it was accessed.

What Should (and Shouldn't) Be Cached Long-Term

Static assets that rarely change -- images, fonts, and especially versioned/hashed filenames like app.a3f9c1.js -- are safe to cache for a long time, since a new deploy simply produces a new filename. The main HTML document, and any API responses with data that changes, generally shouldn't be cached long, or at all, since a stale cached copy would show outdated content.

Note: Pair long cache lifetimes with cache-busting filenames (a hash or version number in the path) for anything that might actually change -- that way you get long caching safely, without users getting stuck on an old file.

Validators: ETag and Last-Modified

Even after a cached copy expires, the browser doesn't necessarily have to re-download the whole file -- it can send a conditional request with the If-None-Match/If-Modified-Since headers, and Apache replies with a cheap 304 Not Modified if the file (identified by its ETag or modification timestamp) hasn't actually changed, saving the bandwidth of re-sending it.

Example: Caching static assets with mod_expires

apacheconf
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpeg "access plus 1 month"
    ExpiresByType image/png "access plus 1 month"
    ExpiresByType text/css "access plus 1 week"
    ExpiresByType application/javascript "access plus 1 week"
</IfModule>
{# Flagged by hand after confirming a runner can't handle this example (a shell command / go.mod file stored as a TopicExample, a language feature the configured runner version doesn't support, or output that blows a runner's sandbox limit) -- see TopicExample.norun. Never render the run button for these, regardless of language, since it would just fail at execute_code (or worse, hang the Judge0 queue on a submission that can never finish cleanly). #}

⚠️ This example can't run in the browser editor. Try it in your own local environment instead.

{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Caching the main HTML page for a long time, so visitors keep seeing an old version of the site after it's updated.
  2. Setting a long cache lifetime on a non-versioned filename that does change, leaving visitors stuck with a stale file until the cache expires.
  3. Forgetting mod_expires needs to be enabled before ExpiresByType/ExpiresDefault directives have any effect.
🔒

Chapter Quiz — Complete all 4 topics to unlock

0/4 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.