A cache tag (from the last lesson) answers "when should this be thrown away?" A cache context answers a different question entirely: "how many separate copies of this do I need to keep in the first place?" Think of a hotel with one message board per floor rather than one for the whole building — the content genuinely varies by which floor you're on, so a single shared board would show the wrong messages to half the guests. A cache context tells Drupal's render cache exactly which "floor" to key its copies by.
What you'll learn in this lesson
- What a cache context is, and how it differs from a cache tag
- How to declare the
'user'context on content that's genuinely personalized - Why the "narrowest context that's still correct" rule matters for real performance
- The most common built-in contexts you'll actually reach for
The real example: a personalized greeting
This exact pattern comes straight from Drupal's own Examples module, in render_example's demo controller:
$build['cache_demonstration'] = [
'#markup' => $this->t('Hello @name, welcome to the #cache example.', [
'@name' => $this->currentUser->getAccountName(),
]),
'#cache' => [
// The "current user" is used above, which depends on the request, so
// we tell Drupal to vary by the 'user' cache context.
'contexts' => [
'user',
],
],
];
Without the contexts key, here's what would actually happen: the first visitor to load this page bakes their own name into the render cache. Every subsequent visitor — including a completely different logged-in user — would then see that first visitor's name, because as far as the render cache is concerned, nothing distinguishes one request from another. Declaring 'user' tells Drupal: "store a separate cached copy of this element for every individual user account," which is exactly the granularity this markup actually needs.
Contexts are hierarchical — narrower is more expensive
| Context | What it varies by |
|---|---|
user | The exact logged-in account — one cached copy per person on the site |
user.roles | Which roles the user has — one copy per unique role combination (often just a handful) |
user.permissions | What the user is allowed to do — similar granularity to roles |
url.path | The current page's path |
languages | The active interface/content language |
"More specific" directly means "more separate cached copies stored." user can produce one cached copy per individual visitor — potentially thousands on a busy site — while user.roles produces one copy per unique role combination, which is usually a very small, stable number. The rule of thumb: always declare the least specific context that still correctly captures how your content varies. If your markup only changes based on whether someone is an administrator, reach for user.roles — not the far more expensive user.
user context (many people, many valid simultaneous copies) and a tag like user:{uid} or an order-specific tag (so it updates the moment that data changes) — one property alone doesn't cover both concerns.Quick check: a block shows different content only depending on whether the visitor is logged in or anonymous — nothing more specific than that. Would
'user'or'user.roles'be the more efficient choice? Reasoning it through: since the variation is really just "authenticated vs. not," the least specific context that still captures it is actually neither of those — it's the coarseruser.roles(an anonymous visitor and every authenticated visitor share the "authenticated" role bucket regardless of which other roles they hold), which produces far fewer cached copies than one-per-account.
Key takeaways
- A cache context controls how many separate cached copies get stored; a cache tag controls when an existing copy is thrown away — they solve different problems and often work together.
- Declare contexts via
'#cache' => ['contexts' => [...]], using the real request-dependent value (like the current user) as your cue for which context applies. - Always reach for the least specific context that's still correct:
user.rolesoruser.permissionsinstead of the far more expensiveuserwhenever the variation is really about group membership, not the individual. - Skipping a needed context doesn't cause an error — it causes the first visitor's personalized content to silently leak to everyone else, which is why this is worth getting right deliberately, not by trial and error.
Coming up next
Tags and contexts are both about doing caching correctly automatically. Sometimes, though, you need to reach in and clear something by hand — the next lesson covers exactly that: clearing cache programmatically, on demand, from your own code.