Tags and contexts both answer "should this cached copy still be used?" based on something happening — a save, a different visitor. But some content goes stale purely because time passes: a "weather right now" block, a countdown timer, a feed of "trending this hour" articles. Nothing explicitly invalidates them; they just need to expire. That's max-age.
What you'll learn in this lesson
- How
max-ageworks as the third piece of Drupal's cache metadata trio - The two special values,
0andCache::PERMANENT, and what each actually means - How max-age interacts with tags and contexts rather than replacing them
Declaring a max-age
use Drupal\Core\Cache\Cache;
$build = [
'#markup' => $this->buildWeatherSummary(),
'#cache' => [
'max-age' => 900, // 15 minutes, in seconds.
],
];
After 900 seconds, Drupal treats this cached element as expired and rebuilds it on the next request, regardless of whether any tag was invalidated. Max-age is measured in seconds and is the simplest of the three cache metadata types — no vocabulary to learn, just a number.
The two values worth knowing by heart
'max-age' => 0— never cache this element at all. Use it for anything that must always be freshly computed: a live view counter, a CSRF-protected form, anything whose staleness would be actively wrong rather than just slightly outdated.Cache::PERMANENT(the implicit default when you omit max-age entirely) — cache forever, until something explicitly invalidates it via a tag. This is the right default for the vast majority of content, since most things only actually change when something tells you they did.
Quick check: you want a "top 10 most-viewed articles this week" block to refresh a bit more often than once a week, even though nothing about "a view happened" is easily tagged. Would you reach for a cache tag, a cache context, or max-age? (Max-age — this is exactly the "goes stale with time, not with a specific event" case it exists for. A modest max-age, like one hour, balances freshness against not recalculating the ranking on every single request.)
Key takeaways
- Max-age expires a cached element after a fixed number of seconds, independent of tags or contexts.
0means never cache;Cache::PERMANENT(the default) means cache until a tag says otherwise.- Tags and max-age are complementary, not alternatives — use tags for event-driven invalidation and max-age as a time-based safety net.
Coming up next
You've now met all three pieces of cache metadata. Next, we look at the operational side: how to clear caches efficiently in day-to-day development and production work, without reaching for a full site-wide flush every time.