You've now tagged content with what it depends on. But some content depends on who's looking — a "Welcome, Sarah" greeting, a block that only admins see, a page that reads differently in French than in English. Cache tags can't express that; that's what cache contexts are for.
What you'll learn in this lesson
- What a cache context does that a cache tag can't
- Common built-in contexts you'll reach for constantly (
user,user.roles,url,languages) - Why picking the least specific context that still works correctly matters for performance
Declaring a context on a render array
$build = [
'#markup' => $this->t('Welcome back, @name!', ['@name' => $this->currentUser->getDisplayName()]),
'#cache' => [
'contexts' => ['user'],
],
];
Declaring the 'user' context tells Drupal's render cache: "store a separate cached copy of this element for every individual user account." Without it, the first visitor to load the page would bake their own name into a cached copy that every subsequent visitor would then see — a real, embarrassing bug that cache contexts exist specifically to prevent.
The contexts you'll use most
user— one cached copy per individual account. The most expensive, most specific option.user.roles— one cached copy per unique combination of roles, often just a handful site-wide, far cheaper thanuser.user.permissions— similar to roles, but grouped by what someone can actually do.url/url.path/url.query_args— vary by the current URL or specific query parameters.languages— vary by the active interface or content language.
Why "least specific" is the rule, not a suggestion
Contexts are hierarchical: user is strictly more specific than user.permissions, which is more specific than user.roles. "More specific" translates directly into "more separate cached copies stored" — user can produce one cached copy per individual person who ever visits, while user.roles produces perhaps five or six copies for the whole site. If your markup only actually changes based on whether someone is an administrator, declaring user instead of user.roles wastes enormous cache storage and hit-rate for no benefit.
Quick check: a block shows different content only for logged-in versus anonymous visitors — never anything more granular than that. Would
'user'or a coarser option be the right context? (A coarser option — something tied purely to authentication status, not the fullusercontext.userwould create a separate cached copy per logged-in account for content that's actually identical across all of them, wasting cache entries for no correctness benefit.)
Key takeaways
- Cache contexts answer "does this vary by visitor," complementing cache tags ("what changed") and max-age ("how long is this valid").
user,user.roles,user.permissions,url, andlanguagesare the contexts you'll reach for constantly.- Always pick the least specific context that's still correct — over-specifying silently wastes cache storage and hit rate.
Coming up next
Tags and contexts cover "what changed" and "who's looking." Next, max-age covers the third dimension: how long a cached item stays valid even if nothing explicitly tells Drupal it changed.