Era Host hosting
EraHost – Free Domain, Cheap Hosting!
Client Area
Support 24/7
Menu

HTTP Cache-Control: max-age with must-revalidate

4 min read
11.05.2025

The Cache-Control: max-age=<seconds>, must-revalidate directive is used to specify the duration a resource should be cached while ensuring the client revalidates the resource with the server after the caching period expires. This provides a balance between performance and content freshness.

Cache-Control must-revalidate
must-revalidate — no stale serving; conditional check after TTL.

For other Cache-Control combination guides, see Cache-Control: max-age — Complete Guide, Cache-Control: max-age for Dynamic Content, and Gzip and Vary: Accept-Encoding.

What Does It Do?

  • max-age=<seconds>: Defines how long (in seconds) a resource can be served from the cache without checking with the server.
  • must-revalidate: Ensures that after the max-age period expires, the client (browser or intermediary cache) must contact the server to verify if the resource is still valid.

Use Cases

  1. Time-Sensitive Content: Content that changes frequently but does not need to be revalidated for every request during its max-age period.
  2. Examples: News articles, API responses, event schedules.
  3. Reliable Freshness: Ensures users always get up-to-date content after the cache duration expires.
  4. Intermediate Cache Control: Prevents stale content from being served by intermediary caches (e.g., CDNs, proxies) without revalidation.
Linux VDS
High performance for your projects
  • Root access and flexible setup
  • Control panel
  • NVMe disks
  • DDR5
Linux VDS

How It Works

  1. Within the Cache Period (max-age): The browser or cache serves the resource without contacting the server. Example: Cache-Control: max-age=600 (10 minutes).
  2. After max-age Expires: The client sends a conditional request (using If-Modified-Since or If-None-Match) to check if the resource has changed. If unchanged, the server responds with 304 Not Modified. If changed, the server sends the updated resource.

Configuration Examples

Apache

Add the following configuration to your .htaccess file or Apache configuration:

<IfModule mod_headers.c>

    <FilesMatch "\.(html|php)$">

        Header set Cache-Control "max-age=600, must-revalidate"

    </FilesMatch>

</IfModule>

This sets a 10-minute cache (max-age=600) for HTML and PHP files and requires revalidation after that.

Restart Apache to apply changes:

sudo systemctl restart apache2

Nginx

Edit your Nginx configuration file to include the Cache-Control header for specific file types:

location ~* \.(html|php)$ {

    add_header Cache-Control "max-age=600, must-revalidate";

}

Reload Nginx:

sudo systemctl reload nginx

PHP

Dynamically set caching headers for resources generated by PHP:

<?php

// Set a 10-minute cache duration with revalidation

header("Cache-Control: max-age=600, must-revalidate");



// Generate dynamic content

echo "This content is cached for 10 minutes but requires revalidation after that.";

?>

API Responses (Node.js Example)

Set Cache-Control headers for an API endpoint:

app.get('/api/data', (req, res) => {

    res.set('Cache-Control', 'max-age=300, must-revalidate');

    res.json({ message: 'This is temporary API data.' });

});

Example Scenarios

Scenario 1: News Page

  • Header: Cache-Control: max-age=300, must-revalidate
  • Behavior: Cached for 5 minutes. After 5 minutes, the browser checks with the server to ensure the news page is up to date.

Scenario 2: API Responses

  • Header: Cache-Control: max-age=120, must-revalidate
  • Behavior: API responses are cached for 2 minutes. After that, clients must revalidate to ensure they get the latest data.

Verifying Configuration

  1. Using cURL: Run the following command to inspect the headers:
  2. curl -I https://yourdomain.com/resource

    Expected Output:

    Cache-Control: max-age=600, must-revalidate
  3. Using Browser Developer Tools:
    • Open Developer Tools (F12).
    • Go to the Network tab.
    • Reload the page and inspect the headers of the requested resource.
  4. Using Online Tools: Use WebPageTest or GTmetrix to analyze caching headers.

Best Practices

  1. Set max-age Appropriately: Use a short duration for time-sensitive resources (e.g., 300 seconds for dynamic content).
  2. Combine with Validation Headers: Add ETag or Last-Modified headers for conditional requests.
  3. Avoid Overuse: Apply must-revalidate only when necessary to balance performance and freshness.
  4. Test Behavior: Verify that caches and clients handle revalidation correctly after the max-age period.

Example Response Headers

HTTP/1.1 200 OK

Content-Type: text/html

Cache-Control: max-age=300, must-revalidate

ETag: "12345"

Last-Modified: Tue, 19 Jan 2025 16:00:00 GMT

By using Cache-Control: max-age with must-revalidate, you can optimize caching for temporary or dynamic content while ensuring users receive up-to-date information after the caching period expires.

Frequently asked questions
In rare error conditions and during the stale-while-revalidate window. If origin is unreachable, caches may serve stale (`stale-if-error`). Some proxies allow stale during background revalidation. For 99% of normal traffic, plain max-age behaves identically to max-age + must-revalidate. The difference matters only in edge cases.
For pages that compute prices, taxes, or confirm orders: yes. Stale served at a moment of error could show a wrong total or duplicate-charge warning. Better to fail-closed (revalidate, return 504 if origin down) than serve a misleading stale page. For static parts of a checkout (CSS, logos), plain max-age is fine.
None until TTL expires — same as plain max-age. After TTL, each request triggers an If-None-Match round-trip. If origin returns 304, only headers transfer (no body) — fast. If origin returns 200 with new body, normal cost. Net impact: one extra round-trip per cache miss vs plain max-age. Negligible for most sites; matters for very-high-volume CDN edges.
must-revalidate overrides stale-while-revalidate's permission to serve stale. They're mutually contradictory directives. Pick one based on intent: must-revalidate = "safety first, never stale"; stale-while-revalidate = "performance first, background refresh." Setting both is a config bug — sniff it during code review.
Related articles
Cache-Control: max-age with public
Cache-Control: max-age for Dynamic Content
Cache-Control: max-age with no-store or no-cache