Cache API
Modern websites are much more dynamic and interactive than 10 years ago, making it more difficult to build modern sites while also being fast
Dries Buytaert
Drupal founder and project lead,
President Drupal Association,
Acquia co-founder and CTO
The fastest Drupal ever is here !
The secret ?

Mostly the new caching strategy
How we use Cache API ?
Typically we return
- render arrays
- Response
cache tags
cache contexts
cache max-age
Cacheability metadata
Cache tags
Drupal 7
Clear cache bin
Clear cache item
Prefix based invalidation
Invalidate all data for user 200
Drupal 7:
Clear the entire cache bin.
Cache tags
Cache tags = data dependencies
Cache tags describe dependencies on data managed by Drupal
There are only two hard things in Computer Science: cache invalidation and naming things.
Phil Karton
What is a cache tag ?
- Type: string[]
- Form: thing:identifier
Example
- node:5 — cache tag for Node entity 5 (invalidated whenever it changes)
- user:3 — cache tag for User entity 3 (invalidated whenever it changes)
- node_list — list cache tag for Node entities (invalidated whenever any Node entity is updated, deleted or created, i.e. when a listing of nodes may need to change)
- config:system.performance — cache tag for the system.performance configuration
- library_info — cache tag for asset libraries
Drupal 8 cache tags
- entities — these have cache tags of the form <entity type>:<entity ID>
- configuration — these have cache tags of the form config:<configuration name>
- custom (for example library_info)
Invalidating
cache_tags.invalidator service
Cache contexts
Cache contexts = (request) context dependencies
Cache contexts are analogous to HTTP's Vary header.
Why ?
Data is context-dependent variation.
- Some expensive-to-calculate data depends on the active theme: different results for different themes. Then you'd vary by the theme cache context.
- When creating a render array that shows a personalized message, the render array varies per user. Then you'd vary (the render array) by the user cache context.
- Generally: when some expensive-to-calculate information varies by some environment context: vary by a cache context.
Example
What ?
A cache context is a string that refers to one of the available cache context services.
Cache contexts are hierarchical.
- vary by user
- vary by permission
How ?
Drupal 8 core ships with the following hierarchy of cache contexts:
cookies
:name
headers
:name
ip
languages
:type
request_format
route
.book_navigation
.menu_active_trails
:menu_name
.name
session
.exists
theme
timezone
url
.host
.query_args
:key
.pagers
:pager_id
.path
.site
user
.is_super_user
.node_grants
:operation
.permissions
.roles
:role- no ambiguity: it's clear what parent cache context is based on wherever it is used
- comparing (and folding) cache contexts becomes simpler: if both a.b.c and a.b are present, it's obvious that a.b encompasses a.b.c, and thus it's clear why the a.b.c can be omitted, why it can be "folded" into the parent
- no need to deal with ensuring each level in a tree is unique in the entire tree
Examples
- theme (vary by negotiated theme)
- user.roles (vary by the combination of roles)
- user.roles:anonymous (vary by whether the current user has the 'anonymous' role or not, i.e. "is anonymous user")
- languages (vary by all language types: interface, content …)
- languages:language_interface (vary by interface language — LanguageInterface::TYPE_INTERFACE)
- languages:language_content (vary by content language — LanguageInterface::TYPE_CONTENT)
- url (vary by the entire URL)
- url.query_args (vary by the entire given query string)
- url.query_args:foo (vary by the ?foo query argument)
Optimizing cache contexts
- a part of the page is varied by user
- another part is varied by user.permissions
optimize([user, user.permissions]) = [user]
Results:
What happens when the permissions change ?
Solution:
- cache tags
- max-age
Example:
user.node_grants
max-age = 0
optimize([user, user.node_grants]) =
[user, user.node_grants]
Example:
user.node_grants
max-age = 3600
optimize([user, user.node_grants]) =
[user]
How to discover and create ?
- cache.context tagged services
- implements \Drupal\Core\Cache\Context\CacheContextInterface
or \Drupal\Core\Cache\Context\CalculatedCacheContextInterface
Example
cache_context.route.book_navigation:
class: Drupal\book\Cache\BookNavigationCacheContext
arguments: ['@request_stack']
tags:
- { name: cache.context}cache_context (mandatory prefix) + route (parents) + book_navigation (this cache context's name)
Debugging
X-Drupal-Cache-Contexts header
Don't you see it ?
Set http.response.debug_cacheability_headers to true in services.yml
Cache max-age
Cache max-age = time dependencies
Cache max-age is analogous to HTTP's Cache-Control header's max-age directive
Why ?
Cache max-age provides a declarative way to create time-dependent caches.
What ?
A cache max-age is a positive integer, expressing a number of seconds.
Cache max-ages are passed around as individual integers, because a given cache item can only logically have a single max-age.
Examples
- 60 means cacheable for 60 seconds
- 100 means cacheable for 100 seconds
- 0 means cacheable for zero seconds, i.e. not cacheable
- \Drupal\Core\Cache\Cache::PERMANENT means cacheable forever, i.e. this will only ever be invalidated due to cache tags. (In other words: ∞, or infinite seconds.)
Big Pipe

RefreshLess
Cache API
By Popdan Daniel
Cache API
- 626