Frequently asked questions 

Why does my entire site cache expire when one page has a future starttime? 

Because the default scoping strategy is global. Its transition lookup covers every monitored table site-wide and ignores the page id, so every page cache entry written in that second gets the same shortened lifetime.

Switching to per-page narrows it — but only for content elements:

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_temporal_cache']['scoping']['strategy'] = 'per-page';
Copied!

A transition in the pages table still shortens every page's lifetime, in every strategy, because a page entering or leaving the tree changes menus everywhere.

Can I disable this for specific page trees? 

Not through configuration. The settings are global to the installation; there is no page-tree, doktype or content-type filter.

The workaround is a second listener on the same event, ordered after this extension's, that overrides the lifetime for the pages it should not apply to:

EXT:my_extension/Classes/EventListener/ConditionalTemporalCache.php
namespace MyVendor\MyExtension\EventListener;

use TYPO3\CMS\Frontend\Event\ModifyCacheLifetimeForPageEvent;

final class ConditionalTemporalCache
{
    /**
     * @param int[] $excludedPageIds pages that keep the long lifetime
     */
    public function __construct(private readonly array $excludedPageIds = [])
    {
    }

    public function __invoke(ModifyCacheLifetimeForPageEvent $event): void
    {
        if (\in_array($event->getPageId(), $this->excludedPageIds, true)) {
            $event->setCacheLifetime(86400);
        }
    }
}
Copied!
EXT:my_extension/Configuration/Services.yaml
services:
  MyVendor\MyExtension\EventListener\ConditionalTemporalCache:
    tags:
      - name: event.listener
        identifier: 'my-extension/conditional-temporal-cache'
        event: TYPO3\CMS\Frontend\Event\ModifyCacheLifetimeForPageEvent
        after: 'temporal-cache/modify-cache-lifetime'
Copied!

Will this work with a CDN or Varnish? 

Yes, with one caveat. A CDN honors the Cache-Control window it is given, so a shortened page cache lifetime propagates to the edge. With global scoping every entry carries the same expiry, so the edge misses arrive together and reach the origin as one wave.

The mitigations are the usual ones — serve stale while revalidating, rate-limit the origin, warm the cache ahead of a known transition — plus the extension-side option of moving to scheduler timing, which stops shortening lifetimes altogether. See Synchronized expiry with global scoping.

Does this affect backend performance? 

The cache lifetime listener runs on frontend page cache writes only, so ordinary backend editing is untouched.

Three parts of the extension do run in the backend, on demand: the backend module, the Reports module status provider, and the console commands. The backend module and the harmonization analysis load temporal records to build their figures, so they get slower as the amount of temporal content grows.

What if I do not use temporal content at all? 

Every lookup returns null and the lifetime falls back to advanced.default_max_lifetime (default 86400), so behavior is unchanged. The queries still run on every page cache write with dynamic timing.

There is no benefit in that case — uninstall it.

How do I see what the extension is doing? 

Turn on advanced.debug_logging. The listener then logs, for every page cache write it modifies: the lifetime it set, the uncapped value, the cap and where the cap came from, and the names of both active strategies.

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_temporal_cache']['advanced']['debug_logging'] = true;
Copied!

The same flag makes SchedulerTimingStrategy log each flush with the tags it flushed, and makes the scheduler task log its run window.

To see the data rather than the decisions:

vendor/bin/typo3 temporalcache:analyze   # counts and statistics
vendor/bin/typo3 temporalcache:list      # every temporal record and its next transition
vendor/bin/typo3 temporalcache:verify    # indexes and configuration
Copied!

Can I combine this with cache warming? 

Yes, and it is worth doing with global scoping, where all entries expire at the same known moment. temporalcache:list reports the next transition per record, so a warming run can be scheduled shortly after it.

The extension ships no warming itself and integrates with no particular warming extension; anything that requests pages after the transition works.

What happens under load when the cache expires? 

With global scoping, every page cache entry expires at the same second, so every subsequent request is a miss until the entries are rebuilt. Under load that arrives at the origin as a single burst.

Four levers, in rough order of effectiveness:

  • scheduler timing — nothing expires by time.
  • per-page scoping — content transitions stagger; page transitions do not.
  • Stale-while-revalidate at the edge, so the burst is absorbed.
  • Cache warming timed to the known transition.

How does this work with workspaces? 

With dynamic timing, correctly and without configuration. The strategies read the workspace id from the Context API and pass it into every query; a live request and a workspace preview therefore resolve different transitions and get different lifetimes.

Can I combine this with my own cache tags? 

Yes. The extension sets the page cache lifetime and, under scheduler timing, flushes pages or pageId_* tags. It does not interfere with tags your own code adds or flushes.

If your listener also sets a lifetime, order it after temporal-cache/modify-cache-lifetime and combine the two values with min() rather than overwriting.

What does harmonization cost? 

Nothing at runtime — it changes no code path. temporalcache:harmonize rewrites the stored starttime/endtime values once, and from then on the same transition lookups simply find fewer distinct moments.

The real cost is editorial: publication times move to the nearest slot within the configured tolerance. Preview with --dry-run before running it, because the command writes by default.

Does the query cost multiply with the number of languages? 

No. One frontend request carries one language, and the language id from the Context API goes into the query as a single sys_language_uid condition. A ten-language site runs the same number of queries per cache write as a single-language site — each language just maintains its own cache entries and its own transitions.

The number of queries grows with the number of monitored tables, at two per table.

Next steps