Cache tags for Extbase plugins and repository auto-tagging 

A cached plugin is fast, but its output must be refreshed when the records it shows change — otherwise visitors keep seeing stale data. The wrong fix is to disable the cache (see Non-cacheable Extbase plugin actions and developer responsibility); the right one is to let the cache stay, and invalidate the caches of affected pages when a record changes.

Cache tags are how TYPO3 does that. Each page-cache entry can be tagged with the records it depends on; clearing a tag flushes every page tagged with it. Extbase can attach these tags for you automatically, so that saving a record through a repository refreshes exactly the pages that display it.

Automatic cache tagging of Extbase repository results 

When a repository query reads records, Extbase can tag the current page cache entry with each record it returned. The tag identifies the table and the record by UID, in the form:

<tablename>_<uid>
Copied!

For a conference with UID 42 in the table tx_myextension_domain_model_conference , the tag is tx_myextension_domain_model_conference_42 . The page that rendered the conference list is tagged with one such tag per conference it displayed. Each tag also carries a lifetime: a default lifetime is attached, and it is shortened when the record has a starttime or endtime , so the page cache expires no later than the record's own visibility window.

Because the tagging is driven by what the query actually returned, you do not maintain any tag list yourself: add a record to the list, and the page that shows the list is tagged with it; change that record later, and clearing its tag flushes the list page automatically.

Enabling automatic cache tagging in Extbase 

Automatic tagging is controlled by the frontend.cache.autoTagging feature toggle. When it is enabled, repository reads tag the page cache as described above; when it is disabled, no tags are added and you must invalidate caches another way — for example with automatic cache clearing or by tagging manually.

You set the toggle in settings.php under SYS/features , or through Admin Tools > Settings > Feature Toggles in the backend.

Adding cache tags manually in an Extbase controller 

Automatic tagging covers the records a repository query returns. When a plugin's output depends on records that were not the query result — related records reached through a relation, an aggregate, or data fetched outside Extbase — those records produce no tag of their own. Add the tags yourself through the frontend cache collector request attribute:

EXT:my_extension/Classes/Controller/ConferenceController.php
<?php

namespace MyVendor\MyExtension\Controller;

use MyVendor\MyExtension\Domain\Repository\ConferenceRepository;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Cache\CacheTag;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

class ConferenceController extends ActionController
{
    public function __construct(
        protected readonly ConferenceRepository $conferenceRepository,
    ) {}

    public function listAction(): ResponseInterface
    {
        $conferences = $this->conferenceRepository->findAll();

        // Auto-tagging tags the conferences the query returned, but not the
        // related location records. Follow the relation and tag each location
        // so the page is flushed when a location changes too:
        $cacheCollector = $this->request->getAttribute('frontend.cache.collector');
        foreach ($conferences as $conference) {
            $location = $conference->getLocation();
            if ($location !== null) {
                $cacheCollector->addCacheTags(
                    new CacheTag('tx_myextension_domain_model_location_' . $location->getUid()),
                );
            }
        }

        $this->view->assign('conferences', $conferences);
        return $this->htmlResponse();
    }
}
Copied!

The example above tags each location by its own UID. Tagging with a table name alone ( tx_myextension_domain_model_location , without a UID) instead tags the page against every record of that table, so any change in the table flushes the page. Use a record-specific tag where you can; use the table-wide tag only when the output genuinely depends on the whole table.

Adjusting an Extbase plugin's page cache tags while it renders 

Inside a plugin action you are building content for one page, and the frontend cache collector request attribute controls the cache tags of that page — the one currently being rendered. Adding or removing a tag changes what the page's cache entry depends on and its lifetime; it does not touch any other page.

Operation Effect
Add tags Tag the page being rendered with a record it depends on, so a change to that record flushes the page.
Remove tags Drop a tag from the page being rendered that it should not carry.

Use it to tag the page being built — as in Adding cache tags manually in an Extbase controller above — or to remove a tag it should not carry:

EXT:my_extension/Classes/Controller/ConferenceController.php
<?php

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Cache\CacheTag;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

class ConferenceController extends ActionController
{
    public function listAction(): ResponseInterface
    {
        $cacheCollector = $this->request->getAttribute('frontend.cache.collector');
        $cacheCollector->removeCacheTags(
            new CacheTag('tx_myextension_domain_model_location_5'),
        );

        return $this->htmlResponse();
    }
}
Copied!

Flushing cached pages from Extbase code after data changes 

Most of the time you do not flush caches by hand — automatic cache clearing resolves the affected pages from the records you changed and flushes them at the end of the request. You need to act directly only when records change outside a rendering request — for example through an import, a command-line task, an event listener. The pages that display those records were cached earlier and must now be flushed. Inject Extbase's cache-clearing helper, which offers these operations:

Operation Effect
Clear specific pages Flush the page cache for one or more page UIDs, by their pageId_<uid> tag.
Clear all pages Flush the entire page cache group. Use sparingly — it discards the cache for the whole site.
Register a record for clearing Record a table and UID whose pages should be flushed at the end of the request. This is what automatic cache clearing uses internally.
EXT:my_extension/Classes/Service/ConferenceImportService.php
<?php

namespace MyVendor\MyExtension\Service;

use TYPO3\CMS\Extbase\Service\CacheService;

class ConferenceImportService
{
    public function __construct(
        protected readonly CacheService $cacheService,
    ) {}

    public function flushAfterImport(int $pageId): void
    {
        // Flush the page cache of specific pages right away:
        $this->cacheService->clearPageCache([$pageId]);

        // Or register a record so the pages showing it are flushed at the end of
        // the request — this is what automatic cache clearing uses internally:
        $this->cacheService->clearCacheForRecord('tx_myextension_domain_model_conference', 42);
    }
}
Copied!

How records trigger cache clearing when they change is the subject of the next page.