Extbase configuration reference 

Most Extbase plugin configuration is written in TypoScript. Some of these settings are read by the Extbase framework itself — they tell Extbase where to find templates, which pages to read records from, and how to behave when an action cannot be resolved. Other configuration will be your own, application-specific, settings that you read inside controllers and Fluid templates. There are two other configuration "blocks" described on this page are not TypoScript: values that an editor feeds in through FlexForms, and installation-wide feature toggles.

This page is the working reference for configuration blocks used by Extbase extensions in practice. For an exhaustive list of TypoScript properties including data type and default value, see the plugin reference in the TypoScript Reference. For the bigger picture of configuration "surfaces" and what belongs in them, see Configure Extbase plugins and modules.

Where Extbase TypoScript lives 

When you register a plugin using \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(), Extbase creates a configuration object in the TypoScript tree. The position in the tree depends on the extension key and the plugin name.

Settings for all an extension's plugins go below plugin.tx_<extensionkey>. The extension key is written without underscores. For an extension with the key EXT:my_extension this will be plugin.tx_myextension.

Settings for single specific plugins go below plugin.tx_<extensionkey>_<pluginname>, for example plugin.tx_myextension_conferencelist. Values set here override the extension-wide values from plugin.tx_myextension.

Backend modules use the same pattern below module.tx_<extensionkey> and module.tx_<extensionkey>_<modulename>.

A few framework settings can also be set globally for every Extbase plugin and module below config.tx_extbase. Use this scope sparingly — plugin-specific configuration is almost always clearer. See The global scope: config.tx_extbase.

The merge order, from lowest to highest precedence, is:

  1. config.tx_extbase (global)
  2. plugin.tx_myextension (extension-wide)
  3. plugin.tx_myextension_conferencelist (plugin-specific)
  4. FlexForm values set by the editor in the content element

FlexForm values therefore take precedence over TypoScript, field by field. A field that an editor leaves blank can still override the matching TypoScript default with its empty value; ignoreFlexFormSettingsIfEmpty (see Output format, language overrides and FlexForm handling) will retain the TypoScript value.

The global scope: config.tx_extbase 

The config.tx_extbase block is the only scope that is not bound to a single extension. Everything below plugin.tx_myextension and plugin.tx_myextension_pluginname configures one extension or one plugin; values placed below config.tx_extbase apply to every Extbase plugin and module in the frontend, no matter which extension ships them. It is the lowest-precedence layer in the merge order above, so any extension- or plugin-level value overrides it.

Only the framework sub-keys are meaningful here — these are the ones read by Extbase itself to steer control flow, namely mvc (error handling) and persistence (class-to-table mapping). The settings and view blocks are inherently application-specific: a global settings value would leak into every third-party plugin, and template paths only make sense for individual extensions. Do not put either there.

A legitimate case is a policy that must hold even for plugins that you do not control. A good example is MVC error handling: "on this site, any Extbase action that cannot be resolved returns 404 rather than silently falling back to a default action". Setting this once globally is more robust than hoping that every installed extension has configured it.

EXT:my_sitepackage/Configuration/Sets/MySitepackage/setup.typoscript
# Site-wide policy: an unresolvable Extbase action is a 404 everywhere,
# for every plugin on the installation — including third-party ones.
config.tx_extbase.mvc {
    throwPageNotFoundExceptionIfActionCantBeResolved = 1
    showPageNotFoundIfTargetNotFoundException = 1
    showPageNotFoundIfRequiredArgumentIsMissingException = 1
}
Copied!

A single plugin can still opt out by overriding the same key under its own plugin.tx_<extensionkey>_<pluginname>.mvc because plugin scope takes precedence over the global scope.

Custom settings: the settings block 

The settings configuration block contains your own configuration values — everything from "how many items per page" to default values for business logic. Extbase makes these available in two places:

  • In controllers in the array $this->settings
  • In every Fluid template in the {settings} variable
EXT:my_extension/Configuration/Sets/MyExtension/setup.typoscript
plugin.tx_myextension {
    settings {
        itemsPerPage = 10
        archive {
            showInSidebar = 1
        }
    }
}
Copied!

The nested value above is read in a controller as $this->settings['itemsPerPage'] and $this->settings['archive']['showInSidebar'], and in Fluid as {settings.itemsPerPage} and {settings.archive.showInSidebar}.

Settings defined for a specific plugin override the extension-wide ones of the same name, and an editor can override individual settings for a content element through the relevant plugin's FlexForm.

"Feeding" settings from a Content Block FlexForm 

Content elements built using Content Blocks and that render an Extbase plugin can pass or "feed" values to $this->settings — without you having to write a FlexForm data structure by hand. This is a little-known but practical trick, and it is becoming more relevant as Content Block technology moves into the Core.

The mechanism is as follows: when a content block reuses the pi_flexform field and defines a FlexForm field whose identifier is settings.<name>, that value is merged into $this->settings['<name>'] exactly like a TypoScript-defined setting. The same applies to the reusable pages and recursive fields, which feed persistence.storagePid and persistence.recursive.

EXT:my_extension/ContentBlocks/ContentElements/conference-list/config.yaml
name: my-vendor/conference-list
group: default
prefixFields: true
prefixType: vendor
fields:
  - identifier: TYPO3/Header
    type: Basic
  # Reuse the existing pages + recursive fields: they feed
  # persistence.storagePid and persistence.recursive
  - identifier: pages
    useExistingField: true
  - identifier: recursive
    useExistingField: true
  # Reuse pi_flexform: any field named settings.* folds into $this->settings
  - identifier: pi_flexform
    type: FlexForm
    useExistingField: true
    fields:
      - identifier: settings.itemsPerPage
        type: Number
Copied!

There are two important things here:

  1. The content block renders through an EXTBASEPLUGIN (Content Blocks provides the rendering definition; you only need to set the pluginName).
  2. Because the element renders as an Extbase plugin and has a pi_flexform value, Extbase's normal FlexForm-to-settings merge applies.

The editor now sees an "Items per page" field in the content element, and the controller reads it as $this->settings['itemsPerPage'] — no custom FlexForm XML is required.

Persistence: storage pages and new-record locations 

The persistence block controls where Extbase reads records from and where it writes new ones.

EXT:my_extension/Configuration/Sets/MyExtension/setup.typoscript
plugin.tx_myextension {
    persistence {
        # Read records from pages 42 and 43 ...
        storagePid = 42,43
        # ... and from four levels of subpages below them
        recursive = 4

        classes {
            # New conferences are written to page 50
            MyVendor\MyExtension\Domain\Model\Conference {
                newRecordStoragePid = 50
            }
            # New speakers are written to a separate folder, page 51
            MyVendor\MyExtension\Domain\Model\Speaker {
                newRecordStoragePid = 51
            }
        }
    }
}
Copied!
storagePid
A comma-separated list of page IDs. Repository read queries return records only from these pages.
recursive
The number of subpage levels below each storagePid that are also searched. The default 0 means only the listed pages themselves are searched.
classes.<FQCN>.newRecordStoragePid
The page ID where new records of a given domain class are stored when the repository persists them. Without it, new records are written to the first configured storagePid. The key is the fully-qualified class name of the domain model. Because the key is based on the class, different models can be stored in different folders — for example new Conference records can be stored on one page and new Speaker records on another, as shown above.
enableAutomaticCacheClearing
Enabled by default. When Extbase persists a change, it clears the page cache for the affected records automatically. See Caching for Extbase plugins for when and why you might disable this.

View: template, partial and layout paths 

The view block tells Extbase where to look for Fluid templates, partials and layouts. Each one is an array of paths. A site package can override an extension's templates without touching the extension itself.

EXT:my_sitepackage/Configuration/Sets/MySitepackage/setup.typoscript
plugin.tx_myextension {
    view {
        // combined path configuration for sitepackage and extension - the higher
        // index is red first and falls back to the lower if no template gets found
        templateRootPaths {
            10 = EXT:my_extension/Resources/Private/Extensions/MyExtension/Templates/
            20 = EXT:my_sitepackage/Resources/Private/Extensions/MyExtension/Templates/
        }
        partialRootPaths {
            10 = EXT:my_extension/Resources/Private/Extensions/MyExtension/Partials/
            20 = EXT:my_sitepackage/Resources/Private/Extensions/MyExtension/Partials/
        }
        // sitepackage does not provide any layouts, so here the extension is the only
        // source to look up
        layoutRootPaths {
            10 = EXT:my_extension/Resources/Private/Extensions/MyExtension/Layouts/
        }
    }
}
Copied!

The default paths and how overriding works 

At render time, ActionController adds the the resource directories in an extension to the configured paths as defaults:

  • EXT:my_extension/Resources/Private/Templates/
  • EXT:my_extension/Resources/Private/Partials/
  • EXT:my_extension/Resources/Private/Layouts/

The default is added at the front of the array, where it acts as the lowest-priority entry. Fluid resolves paths by highest numeric key first and uses the first matching file it finds. The three cases below show what Extbase ends up looking at for templates. These implicit additions are not shown in the TypoScript -> Active TypoScript Backend Module.

Case 1 — no view.templateRootPaths configured. The default is the only path:

Paths Fluid searches (highest key first)
EXT:my_extension/Resources/Private/Templates/
Copied!

Case 2 — an override added under a high key. This is the usual sitepackage override:

EXT:my_sitepackage/Configuration/Sets/MySitepackage/setup.typoscript
plugin.tx_myextension.view.templateRootPaths.10 = EXT:my_sitepackage/Resources/Private/Extensions/MyExtension/Templates/
Copied!
Paths Fluid searches (highest key first)
10  EXT:my_sitepackage/.../Templates/               <- checked first
    EXT:my_extension/Resources/Private/Templates/   (prepended default)
Copied!

Fluid uses your sitepackage template if the file exists there, and otherwise falls back to the extension's own template. Your override does not have to be complete — only the templates you actually want to change need to exist.

Case 3 — the default moved to a different priority. List the default path explicitly under a key of your choice. An explicitly listed default keeps the position you give it instead of being prepended:

EXT:my_sitepackage/Configuration/Sets/MySitepackage/setup.typoscript
plugin.tx_myextension.view.templateRootPaths {
    10 = EXT:my_extension/Resources/Private/Templates/
    20 = EXT:my_sitepackage/Resources/Private/Extensions/MyExtension/Templates/
}
Copied!
Paths Fluid searches (highest key first)
20  EXT:my_sitepackage/.../Templates/        <- checked first
10  EXT:my_extension/Resources/Private/Templates/
Copied!

The same prepend-and-override behaviour applies to partialRootPaths and layoutRootPaths.

Sharing an argument namespace between plugins 

By default every plugin has its own argument namespace: the tx_<extensionkey>_<pluginname>[...] prefix on request arguments and form fields, for example tx_myextension_conferencelist[conference]=5. This isolation is deliberate — two plugins on the same page will not collide.

view.pluginNamespace overrides that prefix. It has two distinct uses:

  1. Shorten the prefix for tidier URLs:

    EXT:my_extension/Configuration/Sets/MyExtension/setup.typoscript
    plugin.tx_myextension_conferencelist.view.pluginNamespace = conf
    Copied!

    Arguments are now conf[conference]=5 instead of the long default.

  2. Deliberately share a namespace between two plugins so that one plugin can read the other's arguments. Point both plugins at the same pluginNamespace:

    EXT:my_extension/Configuration/Sets/MyExtension/setup.typoscript
    plugin.tx_myextension_conferencelist.view.pluginNamespace = conf
    plugin.tx_myextension_conferencefilter.view.pluginNamespace = conf
    Copied!

    A filter plugin and a list plugin sharing the conf namespace can now act on the same arguments — the filter's form submits values that the list plugin reads without the list plugin having to know the filter's plugin name. This is the recommended way to make separate plugins cooperate; do not try to read another plugin's default namespace by guessing its prefix.

    See Generating URLs with the UriBuilder for how namespaces affects generated URIs.

MVC error handling: the mvc block 

The mvc block controls what Extbase does when a request cannot be dispatched to a valid action. There are two separate failure stages, and the settings fall into two corresponding pairs. All accept a boolean (0 or 1) and can be set per plugin or globally in config.tx_extbase.

Stage 1 — the requested action does not exist

These two settings apply when the request asks for an action that is not registered for the plugin at all (a typo in the URL, an action that has been removed, a manipulated request). They are mutually exclusive so you should choose only one:

callDefaultActionIfActionCantBeResolved
Silently fall back to the plugin's first registered action instead of failing. The visitor sees the default action's output. Use this when an unknown action should degrade gracefully to a sensible default view.
throwPageNotFoundExceptionIfActionCantBeResolved
Show a "page not found" (HTTP 404) response instead. Use this when an unknown action should look like a missing page to visitors and search engines rather than silently showing something else.
Stage 2 — the action exists, but argument mapping fails

The action is valid, but Extbase cannot build its arguments. This happens during argument mapping, after the action has been resolved, and is handled by ActionController::handleArgumentMappingExceptions(). The two triggers are different:

showPageNotFoundIfTargetNotFoundException
The argument references a domain object that no longer exists — for example ?tx_myextension_conferencelist[conference]=999 where conference 999 was deleted. Without this setting Extbase throws a \TYPO3\CMS\Extbase\Property\Exception\TargetNotFoundException ; with it, the 404 page is shown. This is the typical "linked record was deleted" case.
showPageNotFoundIfRequiredArgumentIsMissingException
A required argument is absent — the URL omits an argument that the action declares as mandatory. Without this setting, Extbase throws a \TYPO3\CMS\Extbase\Mvc\Exception\RequiredArgumentMissingException; with it, the 404 page is shown.

For behaviour beyond "show the 404 page", for example, logging, redirects, custom error views, override handleArgumentMappingExceptions() in your controller. The default implementation is in ActionController ; copy its signature and inspect the passed \Exception to decide what to do.

EXT:my_extension/Configuration/Sets/MyExtension/setup.typoscript
plugin.tx_myextension {
    mvc {
        throwPageNotFoundExceptionIfActionCantBeResolved = 1
        showPageNotFoundIfTargetNotFoundException = 1
        showPageNotFoundIfRequiredArgumentIsMissingException = 1
    }
}
Copied!

Output format, language overrides and FlexForm handling 

format

format
Type
string
Default
html

Sets the default template file format which determines the template file extension that Extbase looks for. Prefer a dedicated action per output format rather than switching format globally — separate actions keep responsibility for each format in the controller where it is easy to find.

_LOCAL_LANG

Overrides individual translation labels of a plugin without editing its XLF files. The key is the language key (default or an ISO 639-1 code) followed by the translation-unit ID:

EXT:my_extension/Configuration/Sets/MyExtension/setup.typoscript
plugin.tx_myextension_conferencelist._LOCAL_LANG.default.list.heading = Upcoming conferences
plugin.tx_myextension_conferencelist._LOCAL_LANG.de.list.heading = Kommende Konferenzen
Copied!
ignoreFlexFormSettingsIfEmpty
A comma-separated list of FlexForm field names whose empty values should not override the TypoScript settings of the same name. Because FlexForm values take precedence over TypoScript, a field that an editor leaves blank would otherwise overrule a TypoScript default with its empty value; listing the field here will keep the TypoScript value if the field is left blank. The PSR-14 BeforeFlexFormConfigurationOverrideEvent allows further adjustment of the merged configuration.

Extbase feature toggles (not TypoScript) 

Two Extbase behaviours are controlled by global feature toggles rather than by TypoScript. They are set in $GLOBALS['TYPO3_CONF_VARS']['SYS']['features'] (configured through settings.php or the Settings > Feature Toggles backend module) and apply to a whole installation rather than to a single plugin.

extbase.consistentDateTimeHandling
Enabled by default. Aligns Extbase's \DateTime mapping with the FormEngine and DataHandler so that timezones and integer-based time fields behave consistently across the backend and Extbase. See Consistent DateTime handling.
extbase.enableHistoryTracking
Disabled by default (added in TYPO3 v14.2). When enabled, changes persisted by Extbase are recorded in sys_history and shown in the backend record history, similar to backend edits. The toggle enables tracking for all Extbase tables; single tables can opt out via TCA using 'ctrl' => ['extbase' => ['enableHistoryTracking' => false]]. Mind the GDPR implications — full data snapshots are stored. See Feature #107289 and Check Extbase feature toggle defaults after upgrading (TYPO3 v14).

Now that you have configured your plugin, you can move on to writing queries, relations and templates that will turn these settings into a working extension. Start with Persistence layer in Extbase for data considerations and View layer in Extbase for output.