Implementing Granular Cache Invalidation in TYPO3 using Tag-Based Caching
Learn how to implement granular cache invalidation in TYPO3 using tag-based caching to prevent full-site cache flushes and maintain high performance.
23 Oct 2025, 12:39 UTC

The Problem: Over-Caching and Stale Content
In high-traffic TYPO3 installations, caching entire pages is essential for performance, but it creates a conflict: how do you update a single shared element (like a global navigation menu or a footer) across thousands of pages without flushing the entire site cache? A full cache flush spikes CPU load and degrades user experience during the rebuild phase.
The solution is tag-based invalidation. Instead of treating a cache entry as a monolithic block, you associate it with specific tags. When a record changes, you invalidate only the tags associated with that record, leaving unrelated cached content intact.
The Smallest Suitable Design
TYPO3 utilizes a decoupled caching architecture consisting of a Frontend (which handles logic, serialization, and tag management) and a Backend (which handles physical storage).
- Frontend: Typically
VariableFrontend. It manages the mapping between cache identifiers and the tags assigned to them. - Backend: The storage layer. Common choices include
Redis(distributed),Database(standard), orAPCu(local memory).
To implement a custom cache for an extension, you define a configuration in ext_localconf.php. This ensures the system knows which frontend and backend to pair for your specific data needs.
// ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['my_extension_cache'] = [
'frontend' => 'TYPO3\CMS\Core\Cache\Frontend\VariableFrontend',
'backend' => 'TYPO3\CMS\Core\Cache\Backend\RedisBackend',
'backendOptions' => [
'compression' => true,
'defaultLifetime' => 3600,
],
];
Trust and Data Boundaries
When designing cache logic, observe these three boundaries to prevent security leaks and collisions:
- Namespace Isolation: The tag namespace is global. To prevent
Extension Afrom accidentally flushingExtension B's cache, always prefix your tags (e.g., usemyext_product_123instead ofproduct_123). - Input Sanitization: Never use raw user input (like
$_GETparameters) directly as a cache identifier. This can lead to cache poisoning or memory exhaustion. Always hash complex identifiers usingsha1()ormd5(). - Data Sensitivity: Cache backends generally store data in plain text or simple serialization. Do not store PII (Personally Identifiable Information) or session tokens in the cache without an external encryption layer.
Operational Implementation
To use the cache in your PHP code, retrieve the cache instance via the CacheManager and assign tags during the set operation.
// Example: Caching a complex API response
$cacheManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class);
$cache = $cacheManager->getCache('my_extension_cache');
$cacheId = 'api_response_' . md5($requestParams);
if ($cache->get($cacheId) === false) {
$data = $this->fetchExpensiveApiData();
// Assign tags: one for the general group, one for the specific entity
$cache->set($cacheId, $data, ['myext_api_general', 'myext_entity_' . $entityId]);
}
Targeted Invalidation
When the underlying data changes, use the CLI to flush only the relevant tags. This is significantly more efficient than a full system flush.
Run from the TYPO3 root directory as the web user:
./vendor/bin/typo3 cache:flushtags myext_entity_123
Expected Result: Only cache entries tagged with myext_entity_123 are removed. The myext_api_general entries remain valid unless they also shared that specific entity tag.
Failure Modes and Limitations
| Scenario | Impact | Mitigation |
|---|---|---|
| Redis Backend Down | PHP Exceptions / Site Crash | Implement a fallback to FileBackend or ensure Redis high-availability. |
| File Backend Usage | Inconsistent tags across servers | Avoid FileBackend in clustered environments; use a shared Redis instance. |
| DB Backend Load | Table locks during mass flush | Avoid flushing thousands of tags simultaneously; batch the invalidation. |
Verification and Diagnostics
To verify your configuration is active, run the following command to list all registered caches and their assigned backends:
./vendor/bin/typo3 cache:list
To debug if a specific item is being cached, you can temporarily enable caching framework logging in AdditionalConfiguration.php. Check the TYPO3 logs in var/log/ to see HIT or MISS entries for your specific cache identifiers.
When to Change This Design
This architecture is sufficient for most enterprise sites. However, you should reconsider this approach if:
- Migration to v13+: If the core shifts fully to PSR-6/PSR-16, you should wrap your logic in PSR-compliant interfaces to ensure future compatibility.
- Extreme Scale: If internal caching still creates bottlenecks, move the caching boundary to the edge using HTTP Cache headers (ETags) and a Varnish or Nginx FastCGI cache.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.