Published on

TYPO3 Backend Module Essentials

Authors

Let's take a look at how to register a custom TYPO3 backend module, which files are needed and how to render a backend Fluid standalone view.

Create TYPO3 extension skeleton

Use your favorite approach to create a TYPO3 extension skeleton (Extension Builder, your own template, or manual structure). The following examples assume your extension key is my_extension and the PHP namespace is Vendor\MyExtension.

Preparation

Make sure your extension has the typical structure:

my_extension/
├─ Classes/
│  └─ Controller/
├─ Resources/
│  ├─ Private/
│  │  ├─ Layouts/
│  │  ├─ Partials/
│  │  └─ Templates/
│  │     └─ Module/
│  │        └─ Index.html
│  └─ Public/
│     ├─ Css/
│     │  └─ backend.css
│     └─ Icons/
│        └─ module.svg
├─ Configuration/
│  ├─ Backend/
│  │  └─ Routes.php
│  └─ Services.yaml
├─ ext_emconf.php
├─ ext_localconf.php
└─ ext_tables.php

Register the backend module

Register a simple backend module with ExtensionUtility::registerModule() in ext_localconf.php:

<?php

declare(strict_types=1);

use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
use Vendor\MyExtension\Controller\ModuleController;

defined('TYPO3') or die();

ExtensionUtility::registerModule(
    'MyExtension',
    'web', // main area (e.g. 'web', 'system', 'site', ...)
    'module', // sub-identifier
    '', // position
    [
        ModuleController::class => 'index',
    ],
    [
        'access' => 'user,group',
        'icon' => 'EXT:my_extension/Resources/Public/Icons/module.svg',
        'labels' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_module.xlf',
    ]
);

In ext_tables.php you can register additional things like language labels if needed.

Controller

Create a controller at Classes/Controller/ModuleController.php:

<?php

declare(strict_types=1);

namespace Vendor\MyExtension\Controller;

use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

final class ModuleController extends ActionController
{
    public function indexAction(): void
    {
        $this->view->assign('now', (new \DateTimeImmutable())->format(DATE_RFC3339));
    }
}

Fluid template

Create Resources/Private/Templates/Module/Index.html:

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
  <f:layout name="Default" />

  <f:section name="Main">
    <h1>My Backend Module</h1>
    <p>It works! Render time: {now}</p>
  </f:section>
</html>

Optionally add Resources/Private/Layouts/Default.html and reusable partials.

Icon registration (optional)

Register your module icon via Configuration/Services.yaml so TYPO3 can pick it up automatically:

services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  Vendor\\MyExtension\\:
    resource: '../Classes/*'

  my_extension.icon.module:
    class: TYPO3\\CMS\\Core\\Imaging\\IconProvider\\SvgIconProvider
    tags:
      - name: 'typo3.icon'
        identifier: 'my_extension-module'
        source: 'EXT:my_extension/Resources/Public/Icons/module.svg'

Then reference the identifier in your module registration if you prefer identifiers, or keep the file path as shown earlier.

Add CSS/JS to backend (optional)

Add your CSS at Resources/Public/Css/backend.css and include it via ext_localconf.php if needed, e.g. using the backend asset APIs (TYPO3 v12+ offers AssetCollector for backend modules as well).

Routes (advanced)

If you need custom backend routes, place route definitions in Configuration/Backend/Routes.php and map them to your controller actions.

Language labels

Create Resources/Private/Language/locallang_module.xlf to provide labels for the module title, description, and UI strings.

That's it. You now have a basic backend module registered, a controller and a Fluid template rendering content, with optional icon, assets, routes and labels.