I recently got this this question via the feedback form on the bottom of the Cache API Overview tutorial:
“What is the difference between cache keys and cache tags? Why do I need a tag for node:5 when I can just invalidate it using a partial key like [‘node’, 5]?”
After digging into the topic of caching to answer the question, I thought it would also make for a good blog post. This is an excellent question, and it touches on the subtle but important differences between cache keys and cache tags, how they work together to keep your site fast, and provide granular control over cache invalidation.
Let’s start with an example
Imagine you’ve got a node, node/5
, and this node appears in multiple places on your site:
- The rendered page for /node/5 is cached with the key,
['node', 5, 'page']
and the tag,node:5
. - A view that lists, amongst other things, node/5 is cached with the key,
['view', 'recent-content']
and also the tag,node:5
. - A menu containing a link to node/5 is cached with the key,
['menu', 'main-menu']
and the tag,node:5
. - Another node, node/42, that contains an entity reference field which references node/5 and displays its title as part of the content on the page for /node/42 has the tag,
node:5
.
And, you can probably imagine other places that some, or all of this node shows up: like blog listing page titles, search results, or the administrator view at /admin/content.
When you edit node/5, Drupal needs to invalidate the cached data for all the places where that node is used. This includes:
- Invalidating the key
['node', 5]
, which removes only the cached page. - Invalidating the tag
node:5
, which removes all related cached entries like the view, menu, and pages (e.g., node/5, and node/42).
Cache keys: Unique identifiers for cache entries
Cache keys act like exact addresses for individual cache items. They identify a specific piece of cached data and are used when storing or retrieving that data from the cache. If cached data is stored as key/value pairs then cache keys are the key.
For example; a cache key like ['node', 5]
might represent the cache entry for the rendered output of node/5.
Cache keys are precise. When you want to delete or retrieve a specific cache entry, the cache key ensures you’re interacting with the correct data. The specificity of cache keys means they work well for individual items, but they don’t help much when you need to invalidate multiple related items at once.
If node/5 appears in a block, a menu, and a view, each of these items has its own distinct cache key. Invalidation based solely on cache keys would require you to know all of the different places that node/5 is used, and to manage all those cache keys manually.
Cache tags: Grouped invalidation made easy
Cache tags solve this problem by acting as metadata for cache items. Instead of addressing a single cache entry, tags create a relationship between multiple cache entries that are logically related. When a view listing node/5 is built, or the page at node/42 (which contains a reference to node/5) is rendered, the tag node:5
is added to the cache data for the view and the page. Think of it like listing dependencies: this page requires this list of related entities in order to be rendered.
When you invalidate the tag node:5
, all cache entries with that tag are cleared, no matter what their keys are. This is especially useful in a dynamic system like Drupal, where content often appears in many places.
Why not just use partial cache keys?
In practice, you’ll often end up with cache items keyed like entity_view:node:5:teaser:[languages:language_interface]=en...
and entity_view:node:5:card:[languages:language_interface]=en...
. Both are cached version of node/5 represented in two different display modes (teaser and card).
At first glance, it might seem like partial keys (e.g. ['entity_view', 'node', 5]
could do the job. Like a wild card that would clear all entity_view:node:5:*
entries. But here’s why they fall short:
- Exact matching is required: Cache keys are highly specific and must be matched exactly. There’s no built-in mechanism to invalidate a “partial” key like
['entity_view', 'node', 5]
and have it clear all related entries. - Relationships: A node often appears in many places: views, menus, blocks, etc. Each with their own unique keys which will not match
entity_view:node:5:*
. Using cache keys alone would require manually tracking and invalidating every key related to the node, which can quickly become unmanageable.
You need both cache keys and tags
Cache keys and cache tags complement each other:
- Cache keys are for precise identification and retrieval of cache entries. Use cache keys to uniquely identify and retrieve specific cache entries.
- Cache tags enable bulk invalidation of all cache entries related to a specific piece of content. Use cache tags for efficient bulk invalidation when content changes affect multiple cache items.
Learn more
Check out our course on Drupal’s Cache API to learn how to add cache keys, and tags, to your rendered output, how to define custom cache tags, and more.