Naming conventions

The first thing you should decide on is the extension key for your extension and the vendor name. A significant part of the names below are based on the extension key.

Abbreviations & Glossary

UpperCamelCase
UpperCamelCase begins with a capital letter and begins all following subparts of a word with a capital letter. The rest of each word is in lowercase with no spaces, e.g. CoolShop.
lowerCamelCase
lowerCamelCase is the same as UpperCamelCase, but begins with a lowercase letter.
TER
The "TYPO3 Extension Repository": A catalogue of extensions where you can find information about extensions and where you can search and filter by TYPO3 version etc. Once registered on https://my.typo3.org, you can login and register an extension key for your extension in https://extensions.typo3.org My Extensions.
extkey
The extension key as is (e.g. 'my_extension').
extkeyprefix
The extension key with stripped away underscores (e.g. extkey='my_extension' becomes extkeyprefix='myextension').
ExtensionName

The term ExtensionName means the extension key in UpperCamelCase.

Example: for an extkey bootstrap_package the ExtensionName would be BootstrapPackage.

The ExtensionName is used as first parameter in the Extbase method ExtensionUtility::configurePlugin() and as value for the extensionName key when registering a backend module.

modkey
The backend module key.
Public extensions
Public extensions are publicly available. They are usually registered in TER and available via Packagist.
Private extensions
These are not published to the TER or Packagist.

Some of these "Conventions" are actually mandatory, meaning you will most likely run into problems if you do not adhere to them.

We very strongly recommend to always use these naming conventions. Hard requirements are emphasized by using the words MUST, etc. as specified in RFC 2119. SHOULD or MAY indicate a soft requirement: strongly recommended but will usually work, even if you do not follow the conventions.

Extension key (extkey)

The extension key (extkey) is used as is in:

  • directory name of extension in typo3conf/ext (or typo3/sysext for system extensions)

Derived names are:

  • package name in composer.json <vendor-name>/<package-name>. Underscores (_) should be replaced by dashes (-)
  • namespaces: Underscores in the extension key are removed by converting the extension key to UpperCamelCase in namespaces (e.g. cool_shop becomes MyVendor\CoolShop).
  1. The extkey MUST be unique within your installation.
  2. The extkey MUST be made up of lowercase alphanumeric characters and underscores only and MUST start with a letter.
  3. More, see extension key
Examples for extkeys:
  • cool_shop
  • blog

Examples for names that are derived from the extkey:

Here, the extkey is my_extension:

  • namespace: MyVendor\MyExtension\...
  • package name in composer.json: vendor-name/my-extension (the underscore is replaced by a dash)

Vendor name

The vendor name is used in:

  • namespaces
  • package name in composer.json, e.g. myvendor/cool-shop (all lowercase)

Use common PHP naming conventions for vendor names in namespaces and check PSR-0. There are currently no strict rules, but commonly used vendor names begin with a capital letter, followed by all lowercase.

The vendor name (as well as the extkey) is spelled with all lowercase when used in the package name in the file composer.json

For the following examples, we assume:

  • the vendor name is MyCompany
  • the extkey is my_example
Examples:
  • Namespace: MyCompany\MyExample\...
  • package name (in composer.json): my-company/my-example

Database table name

These rules apply to public extensions, but should be followed nevertheless.

Database table names should follow this pattern:

tx_<extkeyprefix>_<table_name>
Copied!
  • <extkeyprefix> is the extension key without underscores, so foo_bar becomes foobar
  • <table_name> should clearly describe the purpose of the table

Examples for an extension named cool_shop:

  • tx_coolshop_product
  • tx_coolshop_category

Extbase domain model tables

Extbase domain model tables should follow this pattern:

tx_<extkeyprefix>_domain_model_<model-name>
Copied!
  • <extkeyprefix> is the extension key without underscores, so foo_bar becomes foobar
  • <model-name> should match the domain model name

Examples for Extbase domain models and table names of an extension named cool_shop:

Domain model Table name
\Vendor\BlogExample\Domain\Model\Post \Vendor\CoolShop\Domain\Model\Tag \Vendor\CoolShop\Domain\Model\ProcessedOrder \Vendor\CoolShop\Domain\Model\Billing\Address tx_blogexample_domain_model_post tx_coolshop_domain_model_tag tx_coolshop_domain_model_processedorder tx_coolshop_domain_model_billing_address

MM-tables for multiple-multiple relations between tables

MM tables (for multiple-multiple relations between tables) follow these rules.

Extbase:

# rule for Extbase
tx_<extkeyprefix>_domain_model_<model-name-1>_<model-name-2>_mm
# example: EXT:blog with relation between post and comment
tx_blogexample_domain_model_post_comment_mm
Copied!

Non-Extbase tables usually use a similar rule, without the "domain_model" part:

# recommendation for non-Extbase third party extensions
tx_<extkeyprefix>_<model-1>_<model-2>_mm
# Example
tx_myextension_address_category_mm

# example for TYPO3 core:
sys_category_record_mm
Copied!

Database column name

When extending a common table like tt_content, column names SHOULD follow this pattern:

tx_<extkeyprefix>_<column-name>
Copied!
  • <extkeyprefix> is the extension key without underscores, so foo_bar becomes foobar
  • <column-name> should clearly describe the purpose of the column

Backend module key (modkey)

The main module key SHOULD contain only lowercase characters. Do not use an underscore or dash.

The submodule key MUST be made up of alphanumeric characters only. It MAY contain underscores and MUST start with a letter.

Example:
  • Coolshop

Example usage:

EXT:my_extension/Configuration/Backend/Modules.php
return [
    // Submodule key
    'web_productmanagement' => [
        // Main module key (use existing main module 'web' here)
        'parent' => 'web',
        // ...
    ],
];
Copied!

For more details have a look into the Modules.php - Backend module configuration chapter.

Backend module signature

The backend module signature is a derived identifier which is constructed by TYPO3 when the module is registered.

The signature is usually constructed by using the main module key and submodule key, separated by an underscore. Conversions, such as underscore to UpperCamelCase or conversions to lowercase may be applied in this process.

Examples (from TYPO3 Core extensions):

  • web_info
  • web_FormFormbuilder
  • site_redirects

Plugin signature

Deprecated since version 13.4

Adding frontend plugins as a "General Plugin", setting the content record CType to 'list' and list_type to the plugin signature is deprecated. See Migration: list_type plugins to CType.

The plugin signature of non-Extbase plugins, registered via ExtensionManagementUtility::addPlugin() is an arbitrarily defined string. By convention it should always be the extension name with all underscores removed followed by one underscore and then a lowercase, alphanumeric plugin key. Examples: "myextension_coolplugin", "examples_pi1".

Extbase based plugins are registered via ExtensionUtility::registerPlugin(). This method expects the extension key (UpperCamelCase or with underscores) as the first parameter and a plugin name in UpperCamelCase (for example "Pi1" or "CoolPlugin"). The method then returns the new plugin signature.

New in version 12.0

Starting with TYPO3 v12.0 the method ExtensionUtility::registerPlugin() automatically returns the correct plugin signature.

If you have to write the signature yourself in other contexts (TypoScript for example) you can build it yourself from the extension name and the plugin name:

For this, all underscores in the extension key are omitted and all characters set to lowercase. The extension key and plugin key are separated by an underscore (_).

Example:

Plugin name and Plugin key listed
$extensionName = 'my_extension';
$pluginName = 'MyCoolPlugin';
$pluginSignature = "myextension_mycoolplugin"
Copied!

The plugin signature is used in:

  • the database field tt_content.CType
  • when defining a FlexForm to be used for the plugin in addPiFlexFormValue()
  • in TypoScript, plugin.tx_myexample_myplugin to define settings for the plugin etc.
  • As record type in TCA. It can therefore be used to define which fields should be visible in the TYPO3 backend.

Example register and configure a non-Extbase plugin:

EXT:examples/Configuration/TCA/Overrides/tt_content_plugin_htmlparser.php
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

$pluginSignature = 'examples_pi1';
$pluginTitle = 'LLL:EXT:examples/Resources/Private/Language/locallang_db.xlf:tt_content.list_type_pi1';
$extensionKey = 'examples';

// Add the plugins to the list of plugins
ExtensionManagementUtility::addPlugin (
    [ $pluginTitle, $pluginSignature,],'CType', $extensionKey
);

ExtensionManagementUtility::addToAllTCAtypes(
    'tt_content',
    '--div--;Configuration,pi_flexform,',
    $pluginSignature,
    'after:header',
);

ExtensionManagementUtility::addPiFlexFormValue(
    '*',
    'FILE:EXT:example/Configuration/FlexForms/Registration.xml',
    $pluginSignature,
);
Copied!
EXT:examples/Configuration/setup.typoscript
plugin.tx_examples_pi1 {
   settings.pageId = 42
}
Copied!

Plugin key (Extbase only)

The plugin key is registered in:

  • second parameter in ExtensionUtility::registerPlugin()

The same plugin key is then used in the following:

  • second parameter in ExtensionUtility::configurePlugin()

The plugin key can be freely chosen by the extension author, but you should follow these conventions:

  • do not use underscore
  • use UpperCamelCase, e.g. InventoryList
  • use alphanumeric characters

For the plugin key, Pi1, Pi2 etc. are often used, but it can be named differently.

The plugin key used in registerPlugin() and configurePlugin() must match or the later method will fail.

Example register and configure an Extbase plugin:

EXT:examples/Configuration/TCA/Overrides/tt_content_plugin_htmlparser.php
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;

$extensionKey = 'Examples';
$pluginName = 'HtmlParser';
$pluginTitle = 'LLL:EXT:examples/Resources/Private/Language/locallang.xlf:htmlparser_plugin_title';

$pluginSignature = ExtensionUtility::registerPlugin(
    $extensionKey,
    $pluginName,
    $pluginTitle
);

// $pluginSignature == "examples_htmlparser"

ExtensionManagementUtility::addToAllTCAtypes(
    'tt_content',
    '--div--;Configuration,pi_flexform,',
    $pluginSignature,
    'after:subheader',
);

ExtensionManagementUtility::addPiFlexFormValue(
    '*',
    'FILE:EXT:example/Configuration/FlexForms/Registration.xml',
    $pluginSignature,
);
Copied!
EXT:examples/ext_localconf.php
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;

ExtensionUtility::configurePlugin(
    'Examples',
    'HtmlParser',
    [
        \T3docs\Examples\Controller\HtmlParserController::class => 'index',
    ],
    ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT,
);
Copied!
EXT:examples/Configuration/setup.typoscript
plugin.tx_examples_htmlparser {
  settings.pageId = 42
}
Copied!

Class name

Class names SHOULD be in UpperCamelCase.

Examples:
  • CodeCompletionController
  • AjaxController

Upgrade wizard identifier

You SHOULD use the following naming convention for the identifier:

extKey_wizardName

This is not enforced.

Please see Wizard identifier in the Upgrade Wizard chapter for further explanations.

Note on "old" extensions

Some the "classic" extensions from before the extension structure came about do not comply with these naming conventions. That is an exception made for backwards compatibility. The assignment of new keys from the TYPO3 Extension Repository will make sure that any of these old names are not accidentally reassigned to new extensions.

Furthermore, some of the classic plugins (tt_board, tt_guest etc) use the "user_" prefix for their classes as well.

Further reading