---
title: "Installation"
manual: "Temporal Cache Management"
version: "main"
source: "Installation/Index.rst"
rendered: "2026-10-07T14:40:31+00:00"
---

# Installation {#installation}

## Requirements {#installation-requirements}

**Minimum**, as declared in `composer.json`:

-   PHP 8.1 or newer
-   TYPO3 `^12.4 || ^13.4 || ^14.3`
-   `typo3/cms-scheduler` and `typo3/cms-reports`, both pulled in as
    dependencies

**Database**

-   Four indexes are added through [`ext_tables.sql`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtTablesSql.html#file-extension-ext-tables-sql), two on `pages` and
    two on `tt_content`; run the database compare after installing
-   No tables and no columns are added — the extension reads the standard
    `starttime` and `endtime` fields

## Compatibility {#installation-compatibility}

The combinations below are the ones the CI matrix in
`.github/workflows/ci.yml` builds.

| TYPO3 version | PHP version | Status | Notes |
| --- | --- | --- | --- |
| 12.4 LTS | 8.1 - 8.4 | ✅ Supported | PHP 8.5 is excluded from this cell in CI |
| 13.4 LTS | 8.2 - 8.5 | ✅ Supported | PHP 8.1 is excluded from this cell in CI |
| 14.3 LTS | 8.3 - 8.5 | ✅ Supported | PHP 8.1 and 8.2 are excluded from this cell in CI |
| 11.5 | — | ⚠️ Not supported | Below the `typo3/cms-core: ^12.4` requirement |

## Installation methods {#installation-methods}

### Method 1: Composer (recommended) {#method-1-composer-recommended}

```bash
composer require netresearch/nr-temporal-cache
vendor/bin/typo3 extension:setup
vendor/bin/typo3 cache:flush
```

`extension:setup` performs the database migrations, which is what creates
the four indexes.

### Method 2: TER (Extension Repository) {#method-2-ter-extension-repository}

1.  Go to **Admin Tools → Extensions**
1.  Click **Get Extensions**
1.  Search for `nr_temporal_cache`
1.  Click **Import and Install**
1.  Activate the extension

### Method 3: Manual installation {#method-3-manual-installation}

1.  Download from [GitHub](https://github.com/netresearch/t3x-nr-temporal-cache/releases)
1.  Extract to `typo3conf/ext/nr_temporal_cache/` (classic mode) or
    `packages/nr_temporal_cache/` (Composer mode)
1.  Activate in the Extension Manager
1.  Clear all caches

## Configuration {#installation-configuration}

### Zero configuration {#zero-configuration}

The extension works immediately after installation.
It automatically:

-   Registers the PSR-14 listener for `ModifyCacheLifetimeForPageEvent` under
    the identifier `temporal-cache/modify-cache-lifetime`
-   Monitors the `pages` and `tt_content` tables
-   Caps the page cache lifetime at the next transition, using global scoping and
    dynamic timing

All twelve settings and their defaults are listed in [Configuration](../Configuration/Index.html#configuration).

### Optional: Monitor custom tables {#optional-monitor-custom-tables}

If you have custom extension tables with `starttime/endtime` fields, you can
register them for temporal cache monitoring using the `TemporalMonitorRegistry`.

Register in [`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php) of your own extension:

**EXT:my_extension/ext_localconf.php**

```php
<?php

defined('TYPO3') or die();

\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
    \Netresearch\TemporalCache\Service\TemporalMonitorRegistry::class
)->registerTable('tx_news_domain_model_news', [
    'uid', 'pid', 'title', 'starttime', 'endtime', 'hidden', 'deleted', 'sys_language_uid'
]);
```

The registry is a `SingletonInterface`, so `makeInstance()` returns the
same instance the extension itself reads, and [`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php) runs
early enough for every later transition lookup to see the table.

> [!WARNING]
> Do not register through a `Services.yaml` entry. A service definition
> that nothing references is removed at container-compile time, so the
> registration never runs and the table is silently not monitored — no error,
> no monitoring. `registerTable()` returns `void` and cannot serve as
> a service factory either.

**Field requirements**

`registerTable()` rejects a registration that misses one of these:

-   `uid`
-   `starttime`
-   `endtime`

Recommended in addition, because the queries and the backend module use them:

-   `pid` — parent page id; for a table with TCA it is read even when the
    registration does not name it, so the scoping strategies flush the page the
    record sits on
-   `hidden` and `deleted` — the transition queries exclude records whose
    TCA `delete` and `enablecolumns.disabled` fields are set
-   `sys_language_uid` — the queries filter on the language of the context when the
    table's TCA names a `languageField` (that column is read even when the
    registration does not name it); tables without workspace or language support
    (no `ctrl.versioningWS`, no `ctrl.languageField`) are queried without those
    conditions
-   a label field such as `title`, `header` or `name` for display

Passing an empty field list applies the default list
`uid, pid, title, starttime, endtime, hidden, deleted, sys_language_uid`.

**Default tables**

`pages` and `tt_content` are monitored out of the box.
Re-registering either of them throws an exception.

Each registered table adds two `MIN()` queries to a transition lookup — see
[High database load](../Configuration/Troubleshooting.html#configuration-troubleshooting-performance).

### Optional: Adjust the maximum lifetime {#optional-adjust-the-maximum-lifetime}

`advanced.default_max_lifetime` caps the cache lifetime the extension
calculates, and is the lifetime used when no transition is scheduled at all.

**Default**: 86400 seconds (24 hours)

Configure it in **Admin Tools → Extensions → nr_temporal_cache →
Configure**, under **Default Cache Lifetime (seconds)**, or in PHP:

**config/system/additional.php**

```php
<?php

$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_temporal_cache']['advanced']['default_max_lifetime'] = 43200;
```

TypoScript `config.cache_period` takes precedence over this setting; see
[Advanced options](../Configuration/Advanced.html#configuration-advanced).

## Verification {#installation-verification}

### Check the setup {#check-the-setup}

```bash
vendor/bin/typo3 temporalcache:verify
```

The command confirms that the indexes and the columns the queries rely on
exist, and that the configured strategy names are valid.
**System → Reports → Temporal Cache** shows the same configuration from
the backend.

### Test scheduled content {#test-scheduled-content}

1.  Create a test page:

    -   Set **Start** to 5 minutes in the future
    -   Enable **In menu**
    -   Save
1.  Check the frontend menu — the page must not appear yet
1.  Wait until the start time and reload — the page appears without any cache
    being cleared by hand

The page cache lifetime is capped at the transition, so the first request after
the start time regenerates the page.

### Test expiring content {#test-expiring-content}

1.  Create a content element with **Stop** 5 minutes in the future
1.  View the page — the element is visible
1.  Wait until the stop time and reload — the element is gone

### Inspect what the extension calculated {#inspect-what-the-extension-calculated}

```text
advanced.debug_logging = 1
```

Each page cache generation then logs the lifetime that was written, the
uncapped value, and which maximum applied.
See [Advanced options](../Configuration/Advanced.html#configuration-advanced).

## Troubleshooting {#installation-troubleshooting}

### Content does not update {#content-does-not-update}

1.  Confirm the extension is loaded:

    ```php
    vendor/bin/typo3 extension:list
    ```
1.  Confirm the timing strategy.
    `scheduler` always depends on the scheduler task, and `hybrid` does when
    at least one of `timing.hybrid.pages` and `timing.hybrid.content` is set
    to `scheduler`.
    In those cases confirm the task exists and cron is running it — see
    [Scheduler task](../Configuration/Advanced.html#scheduler-setup).
    A `hybrid` configuration with both rules on `dynamic` needs no task.
1.  Clear all caches:

    ```php
    vendor/bin/typo3 cache:flush
    ```
1.  Work through [Troubleshooting](../Configuration/Troubleshooting.html#configuration-troubleshooting)

### Slow page generation {#slow-page-generation}

The dynamic timing strategy runs two `MIN()` queries per monitored table on
every page cache generation.
Confirm the indexes exist:

```sql
SHOW INDEX FROM pages WHERE Key_name LIKE 'idx_temporalcache%';
SHOW INDEX FROM tt_content WHERE Key_name LIKE 'idx_temporalcache%';
```

If they are missing, run the database compare — the definitions ship with the
extension:

```bash
vendor/bin/typo3 extension:setup
```

To log the extension's own messages into a separate file:

**config/system/additional.php**

```php
<?php

$GLOBALS['TYPO3_CONF_VARS']['LOG']['Netresearch']['TemporalCache']['writerConfiguration'] = [
    \TYPO3\CMS\Core\Log\LogLevel::DEBUG => [
        \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
            'logFile' => 'typo3temp/var/log/temporal_cache.log',
        ],
    ],
];
```

### Workspace and language {#workspace-and-language}

Every transition query resolves the workspace and the language from the
`Context` API and filters on both.
A transition scheduled in another language therefore does not shorten the
lifetime of the page you are looking at.

## Uninstallation {#installation-uninstallation}

The extension adds no tables and no columns.
It does add four indexes to `pages` and `tt_content`
(`idx_temporalcache_starttime` and `idx_temporalcache_endtime`, see
[`ext_tables.sql`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtTablesSql.html#file-extension-ext-tables-sql)); remove them in **Admin Tools → Maintenance →
Analyze Database Structure** after uninstalling if you do not want to keep them.

```bash
composer remove netresearch/nr-temporal-cache
vendor/bin/typo3 cache:flush
```

TYPO3 then reverts to its default behaviour: temporal content becomes visible
when the page cache happens to expire.

## Next steps {#next-steps}

-   [Configuration](../Configuration/Index.html#configuration) \- Every setting and its default
-   [Architecture](../Architecture/Index.html#architecture) \- How the listener, strategies and repository fit together
-   [GitHub issues](https://github.com/netresearch/t3x-nr-temporal-cache/issues) \- Report problems
