Mastering TYPO3 v13: The Essential Guide for Upgrades and Migrations

Mastering TYPO3 v13: The Essential Guide for Upgrades and Migrations

TYPO3 v13 is a major step forward. It removes legacy APIs, tightens core architecture, and introduces stricter standards that directly affect custom code and extensions.

This guide focuses on what matters during an upgrade: breaking changes that must be fixed, important changes that may alter behaviour, and deprecations that need attention before TYPO3 v14. Use it as a practical reference to plan, execute, and stabilise your TYPO3 v13 migration with fewer surprises.

This guide is for teams planning a serious upgrade to TYPO3 v13. It focuses on real migration work and long-term maintenance, not feature marketing.

This guide is for

  • TYPO3 agencies managing multiple client projects and LTS upgrades
  • Freelance TYPO3 developers maintaining custom extensions and site packages
  • In-house TYPO3 teams running long-living, business-critical websites
  • Technical leads and CTOs planning upgrade scope, risk, and timelines

This guide is not for

  • Beginners new to TYPO3
  • Marketing or content-only roles
  • Projects running close to TYPO3 core without custom code or extensions

What you will gain

  • Clarity on which breaking changes require immediate action
  • Guidance on what can be postponed without upgrade risk
  • A practical view on preparing TYPO3 v13 projects for v14
     

TYPO3 upgrades are not just technical tasks. They are planning exercises shaped by long lifecycles, extension dependencies, and limited upgrade windows.

Long LTS Cycles Shape Every Decision

TYPO3 projects often run 3–6 years on one LTS version.

That means:

  • Old decisions stay in production longer
  • Technical debt compounds quietly
  • Upgrade mistakes are expensive to undo

v13 upgrades should be treated as structural resets, not quick version bumps.

Extension-First Dependency Reality

Most TYPO3 installations depend more on extensions than core.

In practice:

  • Core upgrades block on extension readiness
  • Custom extensions are the highest-risk area
  • TER extensions vary widely in maintenance quality

Always audit extensions before touching custom code.

What to Fix First (Blocking Issues)

Fix these before or during the upgrade:

  • Breaking changes that cause PHP errors or fatal exceptions
  • Removed hooks replaced by PSR-14 events
  • QueryBuilder, Doctrine, and Symfony incompatibilities
  • Deprecated APIs scheduled for removal in v14

These will break the site, not just log warnings.

What Can Wait (Post-Upgrade Cleanup)

These can be scheduled after stabilization:

  • Deprecated but still functional APIs
  • Internal refactoring for cleaner architecture
  • Performance tuning unrelated to v13 changes

Delaying these is acceptable, but track them.

This mindset keeps TYPO3 v13 upgrades predictable, controlled, and aligned with long-term maintenance, not just version compliance.

This section focuses on what actually reduces upgrade time and risk in real TYPO3 projects. It reflects patterns seen across agency deliveries, long-running sites, and extension maintenance.

Recommended Upgrade Path

  • Upgrade to the latest TYPO3 v12 LTS first.
  • Resolve all deprecations and extension warnings in v12.
  • Only then move to v13, using the core upgrade wizards.
  • Avoid skipping major versions on active projects.

This two-step path catches most breaking changes early and keeps rollback simple.

Pre-Upgrade Checks (Do These First)

  • Confirm all extensions are v13-compatible or maintained.
  • Remove unused or abandoned TER extensions.
  • Run TYPO3 deprecation logs and fix warnings in v12.
  • Check custom code for:
    • Hook usage (stdWrap, TSFE, IconFactory)
    • QueryBuilder and Doctrine usage
    • Backend JavaScript module imports

Skipping these checks is the most common cause of failed upgrades.

Upgrade Sequence That Actually Works

  1. Update PHP and system requirements.
  2. Upgrade TYPO3 core via Composer.
  3. Run all Install Tool wizards.
  4. Clear caches and recheck backend access.
  5. Fix fatal errors before touching frontend output.

Do not debug frontend issues until the backend is stable.

Post-Upgrade Validation

  • Test backend forms, RTE, and custom modules.
  • Verify login, permissions, and workspaces.
  • Check CLI commands and scheduler tasks.
  • Review logs for remaining deprecations or notices.

Most hidden issues appear in backend workflows, not pages.

Common Mistakes TYPO3 Teams Make

  • Treating deprecations as optional cleanup.
  • Keeping legacy hooks instead of moving to PSR-14.
  • Mixing runtime fixes with Composer updates.
  • Letting strict typing issues surface in production.

These increase long-term maintenance costs, not just upgrade effort.

Extension Author Perspective (What Matters Now)

TYPO3 v13 enforces clearer architecture:

  • PSR-14 events replace most legacy hooks.
  • Strict typing is no longer optional in Extbase.
  • Composer discipline matters for dependency stability.

Extensions that follow these rules upgrade cleanly. Others become technical debt quickly.

This table helps teams understand which changes are mandatory now and which are future blockers. It is ideal for AI snippets and featured answers.

AreaTYPO3 v13 StatusTYPO3 v14 ImpactWhat Teams Should Do
Legacy HooksRemovedNot availableMigrate fully to PSR-14 events
QueryBuilder APIsChangedStableUpdate now; v14 will not support legacy calls
Extbase TypingEnforcedStricterFix type hints and method signatures
$GLOBALS['TSFE']DeprecatedRemovedUse Context API or request attributes
Fluid renderStatic()DeprecatedRemovedRefactor ViewHelpers
Plugin via list_typeDeprecatedRemovedUse dedicated CType per plugin
CKEditor config fallbacksRemovedStableUse explicit YAML arrays
Backend JS legacy modulesDeprecatedRemovedSwitch to modern ES modules
PageTS via APIDeprecatedRemovedMove to configuration files
Datetime INT fieldsChangedStableEnsure BIGINT usage

Key takeaway:
A TYPO3 v13 upgrade that ignores deprecations is only half done. Fixing them now dramatically lowers v14 effort.

TYPO3 v13 introduces significant internal changes. Not all of them require the same level of urgency. To support realistic upgrade planning, the changes below are grouped by actual project risk, not by changelog category.

This helps teams decide:

  • What must be fixed before upgrading
  • What needs testing after the upgrade
  • What can be handled later as cleanup for v14

High-Risk Changes (Must Be Fixed Before or During Upgrade)

These changes will break functionality or cause fatal errors if not addressed.

QueryBuilder and Database API Changes

ExpressionBuilder Changes

The method signatures have changed:

  • ExpressionBuilder::literal() now strictly requires a string
  • ExpressionBuilder::trim() now requires the TrimMode enum

Before v13

$queryBuilder->expr()->comparison(
    $queryBuilder->expr()->trim($fieldName, 1),
    ExpressionBuilder::EQ,
    $queryBuilder->createNamedParameter('', Connection::PARAM_STR)
);

After v13

use Doctrine\DBAL\Platforms\TrimMode;

$queryBuilder->expr()->comparison(
    $queryBuilder->expr()->trim($fieldName, TrimMode::LEADING),
    ExpressionBuilder::EQ,
    $queryBuilder->createNamedParameter('', Connection::PARAM_STR)
);
QueryBuilder API Changes

Removed methods include:

add()
getQueryPart(), getQueryParts()
resetQueryPart(), resetQueryParts()
execute()
setMaxResults(0)

Required changes

  • Use executeQuery() for SELECT
  • Use executeStatement() for INSERT / UPDATE / DELETE
  • Use null instead of 0 for unlimited results

Before v13

$queryBuilder->add('select', ['uid', 'title']);
$result = $queryBuilder->execute();
$queryBuilder->setMaxResults(0);

After v13

$queryBuilder->select('uid', 'title');
$result = $queryBuilder->executeQuery();
$queryBuilder->setMaxResults(null);

Authentication and Context Access

LoginType Converted to Native Enum

\TYPO3\CMS\Core\Authentication\LoginType is now a PHP enum.
Old constants are removed.

Before v13

if ($loginType === \TYPO3\CMS\Core\Authentication\LoginType::LOGIN) {
    // ...
}

After v13

use TYPO3\CMS\Core\Authentication\LoginType;

if (LoginType::tryFrom($value ?? '') === LoginType::LOGIN) {
    // login
}

$TSFE->fe_user Removed

Direct access to frontend user data via $TSFE is no longer available.

Before v13

$username = $GLOBALS['TSFE']->fe_user->user['username'];

After v13 (Context API)

use TYPO3\CMS\Core\Context\Context;

$username = $this->context
    ->getPropertyFromAspect('frontend.user', 'username', '');

After v13 (Request attribute)

$frontendUser = $this->request->getAttribute('frontend.user');
$username = $frontendUser->user['username'] ?? '';

Removed Hooks (PSR-14 Required)

The following hooks are fully removed and will cause failures if still referenced:

  • stdWrap hook
  • getData hook
  • postInit hook
  • Icon overlay override hook

Action required

  • Remove hook registrations
  • Replace with corresponding PSR-14 events

Backend Layout Provider Change

PageTsBackendLayoutDataProvider Marked Final

\TYPO3\CMS\Backend\View\BackendLayout\PageTsBackendLayoutDataProvider can no longer be extended.

Before v13

class MyProvider extends PageTsBackendLayoutDataProvider {
}

After v13

class MyProvider implements BackendLayoutDataProviderInterface {
}

Medium-Risk Changes (Behaviour Changes After Upgrade)

These changes may not crash the system but alter behaviour, output, or editor experience.

CKEditor Configuration Change

removePlugins Fallback Removed

String-based configuration is no longer supported.

Before v13

editor:
  config:
    removePlugins: image

After v13

editor:
  config:
    removePlugins:
      - image

Indexed Search Changes

Indexed Search Declared as Content Element

EXT:indexed_search is now a CType instead of a plugin.

Action

  • Run upgrade wizard:
    “Migrate Indexed Search plugins to content elements”

Pagination Changes

getAllPageNumbers() Removed

This method no longer exists.

Action

  • Use getFirstPageNumber()
  • Use getLastPageNumber()
  • Or implement custom iteration logic
     

Utility Behaviour Changes

Continuous Array Keys in intExplode()

When removeEmptyEntries = true, keys are now continuous.

Before

[0 => 1, 2 => 3]

After

[0 => 1, 1 => 3]

Editor & Wizard Behaviour

New Content Element Wizard Derived from TCA

show := removeFromList() no longer works.

Required change

removeItems := addToList(html)

SEO & Link Validation

External Link Validation Disabled by Default

EXT:linkvalidator no longer checks external links unless enabled.

Action

mod.linkvalidator.linktypes = db,file,external

Default twitter_card Changed

Default value changed from summary to summary_large_image.

Low-Risk Changes (Cleanup and v14 Preparation)

These changes do not block TYPO3 v13 but should be addressed to reduce future upgrade effort.

Database & Schema

BIGINT for Datetime Fields

Datetime TCA fields now use BIGINT to avoid the year-2038 problem.

Before

crdate INT(11) DEFAULT '0'

After

crdate BIGINT(20) DEFAULT '0'

Dependency Updates

  • Symfony upgraded to version 7
  • Doctrine DBAL upgraded to version 4

These are mostly covered by QueryBuilder fixes above.

Removed Legacy Structures

  • Unused tt_content fields removed
  • cache_treelist table removed

Only impacts projects still referencing them.

Indexed Search Customisation

Manipulating final search queries in EXT:indexed_search has changed. Only relevant if custom logic exists.

How to Apply This in Practice

  • Fix High-Risk changes before upgrading
  • Test Medium-Risk changes during QA
  • Schedule Low-Risk changes as cleanup

This avoids unnecessary work and keeps TYPO3 upgrades predictable and controlled.

The following APIs and patterns are still available in TYPO3 v13, but will be removed in TYPO3 v14. They do not block an immediate upgrade, but leaving them unresolved will increase future upgrade effort.

Recommendation:

Fix these during v13 upgrade work where possible, especially in extensions you actively maintain.

1. ExtensionManagementUtility::addPageTSConfig()

This method is deprecated and will be removed in v14.

What to do:

Move Page TS configuration into a dedicated Configuration/page.tsconfig file.

2. DuplicationBehavior Class

The legacy class is deprecated.

Before:

$behavior = \TYPO3\CMS\Core\Resource\DuplicationBehavior::RENAME;

After:

$behavior = \TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior::RENAME;

3. AbstractFile::FILETYPE_* Constants

All AbstractFile::FILETYPE_* constants are deprecated.

Before:

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_UNKNOWN
\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_TEXT
\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_IMAGE
\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_AUDIO
\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_VIDEO
\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_APPLICATION

After:

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_UNKNOWN -> \TYPO3\CMS\Core\Resource\FileType::UNKNOWN->value

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_TEXT -> \TYPO3\CMS\Core\Resource\FileType::TEXT->value

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_IMAGE -> \TYPO3\CMS\Core\Resource\FileType::IMAGE->value

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_AUDIO -> \TYPO3\CMS\Core\Resource\FileType::AUDIO->value

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_VIDEO -> \TYPO3\CMS\Core\Resource\FileType::VIDEO->value

\TYPO3\CMS\Core\Resource\AbstractFile::FILETYPE_APPLICATION -> \TYPO3\CMS\Core\Resource\FileType::APPLICATION->value

Apply the same change for TEXT, AUDIO, VIDEO, APPLICATION, and UNKNOWN.

4. DataProviderContext Getters and Setters

Since TYPO3 v13.4, DataProviderContext uses constructor property promotion and is moving to a readonly, final class in v14.

Before (setter-based):

$dataProviderContext = GeneralUtility::makeInstance(DataProviderContext::class);
$dataProviderContext
    ->setPageId($pageId)
    ->setData($parameters['row'])
    ->setTableName($parameters['table'])
    ->setFieldName($parameters['field'])
    ->setPageTsConfig($pageTsConfig);

After (constructor-based):

$dataProviderContext = new DataProviderContext(
    pageId: $pageId,
    tableName: $table,
    fieldName: $field,
    data: $row,
    pageTsConfig: $pageTsConfig
);

Access properties directly instead of getters.

Before

$pageId = $dataProviderContext->getPageId()

After

$pageId = $dataProviderContext->pageId

5. TypoScriptFrontendController and $GLOBALS['TSFE']

TypoScriptFrontendController and $GLOBALS['TSFE'] are deprecated and removed in v14.

What to do:

Use request attributes or the Context API.

Before v13

$feUser = $GLOBALS['TSFE']->fe_user->user;

After v13

use TYPO3\CMS\Core\Context\Context;

$feUser = GeneralUtility::makeInstance(Context::class)
	->getPropertyFromAspect('frontend.user', 'user');

6. Fluid Standalone Methods

Several standalone Fluid methods like TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper->registerUniversalTagAttributes() and AbstractTagBasedViewHelper->registerTagAttribute() are deprecated.

Impact:

Custom ViewHelpers may trigger warnings.

Action:

Review Fluid extensions and follow current Fluid API documentation.

7. Table-Dependent columnsOnly Definition

The columnsOnly parameter must now be defined per table.

Before:

$urlParameters = [
    'edit' => [
        'pages' => [
            1 => 'edit',
        ],
    ],
    'columnsOnly' => 'title,slug'
    'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri(),
];

GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('record_edit', $urlParameters);

After:

$urlParameters = [
    'edit' => [
        'pages' => [
            1 => 'edit',
        ],
    ],
    'columnsOnly' => [
        'pages' => [
            'title',
            'slug'
        ]
    ],
    'returnUrl' => $request->getAttribute('normalizedParams')->getRequestUri(),
];

GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('record_edit', $urlParameters);

8. Namespaced Shorthand Validators in Extbase

Namespaced shorthand validator notation is deprecated.

Before:

/**
 * @Extbase\Validate("TYPO3.CMS.Extbase:NotEmpty")
 */
protected $myProperty1;

/**
 * @Extbase\Validate("Vendor.Extension:Custom")
 */
protected $myProperty2;

After:

/**
 * @Extbase\Validate("NotEmpty")
 */
protected $myProperty1;

/**
 * @Extbase\Validate("Vendor\Extension\Validation\Validator\CustomValidator")
 */
protected $myProperty2;

Or

#[Extbase\Validate(['validator' => \TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator::class])]
protected $myProperty1;

#[Extbase\Validate(['validator' => \Vendor\Extension\Validation\Validator\CustomValidator::class])]
protected $myProperty2;

Custom validators must use full class names.

9. Custom Fluid Views in Extbase

StandaloneView, TemplateView, and related classes are deprecated.

Replacement:

Use ViewFactoryInterface.

This affects custom Extbase rendering logic.

10. renderStatic() in Fluid ViewHelpers

renderStatic() and related traits are deprecated.

Before:

class MyViewHelper extends AbstractViewHelper
{
	use CompileWithRenderStatic;

	public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext): string
	{
	    	return $renderChildrenClosure();
	}
}

After:

class MyViewHelper extends AbstractViewHelper
{
	public function render(): string
	{
    	return $this->renderChildren();
	}
}

Refactor ViewHelpers accordingly.

11. IconRegistry Instantiation in ext_localconf.php

Manual icon registration in ext_localconf.php is deprecated.

Before v13

EXT:example/ext_localconf.php
<?php
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class,);
$iconRegistry->registerIcon(
	'example',
	\TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
	[
    	'source' => 'EXT:example/Resources/Public/Icons/example.svg'
	],
);

Nach v13

EXT:example/Configuration/Icons.php
<?php
return [
	'example' => [
    		'provider' => \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
	    	'source' => 'EXT:example/Resources/Public/Icons/example.svg',
	],
];

12. INCLUDE_TYPOSCRIPT Syntax

The <INCLUDE_TYPOSCRIPT:> syntax is deprecated.

Before v13

<INCLUDE_TYPOSCRIPT: source="FILE:EXT:my_extension/Configuration/TypoScript/myMenu.typoscript">

After v13

@import 'EXT:my_extension/Configuration/TypoScript/myMenu.typoscript'

13. Plugin Content Element and SubTypes

Registering plugins via list_type is deprecated.

TYPO3 v14 approach:

Each plugin must have its own CType.

14. @typo3/backend/wizard.js

The legacy wizard module is deprecated.

Replacement:

@typo3/backend/multi-step-wizard.js

Required for backend wizard extensions.

Before v13

import Wizard from '@typo3/backend/wizard.js';
Wizard.addSlide(
 	'My-slide-identifier',
 	'Slide title',
 	'Content of my slide',
 	SeverityEnum.notice,
 	function () {
	     	// callback executed after displaying the slide
 	}
);

After

import MultiStepWizard from '@typo3/backend/multi-step-wizard.js';
MultiStepWizard.addSlide(
 	'my-slide-identifier',
 	'Slide title',
 	'Content of my slide',
 	SeverityEnum.notice,
	'My step',
 	function () {
	     	// callback executed after displaying the slide
 	}
);

15. Page Tree Navigation Component ID

The page tree component ID has been renamed.

Old:

@typo3/backend/page-tree/page-tree-element

New:

@typo3/backend/tree/page-tree-element

Update custom backend modules accordingly.

16. GeneralUtility::hmac()

GeneralUtility::hmac() is deprecated.

Replacement:

HashService::hmac()

Use dependency injection or GeneralUtility::makeInstance().

Before v13

$hmac = GeneralUtility::hmac('some-input', 'some-secret');

After v13

use TYPO3\CMS\Core\Crypto\HashService;

$hashService = GeneralUtility::makeInstance(HashService::class);$hmac = $hashService->hmac('some-input', 'some-secret');

17. Fluid Variables: true, false, null

Fluid no longer allows variables named true, false, or null.

Action:

Rename conflicting variables to avoid runtime exceptions.

Before v13

<f:variable name="true" value="someValue" />

After v13

<f:variable name="myTrue" value="someValue" />

How to Handle Deprecations in Practice

  • Do not block your v13 upgrade for deprecations alone
  • Fix deprecations in actively maintained extensions
  • Remove deprecated APIs in custom code you control
  • Leave third-party extensions for vendor updates if needed

Addressing these early will significantly reduce effort when moving to TYPO3 v14.

Use this as a final check before and after your v13 upgrade.

Before the Upgrade

  • Review and fix breaking changes in custom code
  • Replace removed hooks with PSR-14 events
  • Check extensions for v13 compatibility
  • Resolve all deprecations reported in v12

During the Upgrade

  • Run all Upgrade Wizards in the Install Tool
  • Validate database schema and TCA changes
  • Clear caches and confirm backend access

After the Upgrade

  • Test backend workflows, RTE, and custom modules
  • Verify frontend rendering and critical user flows
  • Search the codebase for deprecated APIs and constants
  • Monitor logs for remaining warnings or notices

Projects that treat these steps as mandatory, not optional, avoid most upgrade regressions and reduce long-term maintenance risk.

TYPO3 v13 tightens the platform in the right places. Legacy hooks are gone, APIs are clearer, and dependencies are modern. The upgrade is manageable if handled methodically. 

Projects that address breaking changes early and clean up deprecations now will move into TYPO3 v14 with far less effort.

Yes. TYPO3 v14 removes APIs and patterns that are only deprecated in v13. Skipping v13 means dealing with breaking changes and deprecations at the same time, which significantly increases upgrade risk. A clean v13 upgrade reduces effort and makes the v14 transition predictable.

Custom extensions are the most common failure point. Removed hooks, QueryBuilder API changes, stricter typing in Extbase, and deprecated access to $GLOBALS['TSFE'] often cause fatal errors. Core-only projects with minimal customization usually upgrade with fewer issues.

Yes, but it is not recommended. Deprecations do not block TYPO3 v13, but leaving them unresolved increases technical debt and makes the v14 upgrade harder. Deprecations in actively maintained extensions should be fixed during the v13 upgrade cycle.

Extensions should be audited first. TYPO3 upgrades are often blocked by incompatible extensions, not core changes. Fix or replace unsupported extensions before refactoring custom code. Custom extensions usually require more work than site packages or templates.

It depends on project complexity. Simple projects may upgrade in a few days. Projects with multiple custom extensions and legacy hooks often require several weeks, including testing and cleanup. Planning and extension audits have more impact than raw development speed.

Treating deprecations as optional and postponing architectural fixes. Legacy hooks, loose typing, and outdated APIs may still work in v13 but will fail in v14. Fixing them early reduces long-term maintenance cost and avoids rushed upgrades later.

Your One-Stop Solutions for Custom TYPO3 Development

  • A Decade of TYPO3 Industry Experience
  • 350+ Successful TYPO3 Projects
  • 87% Repeat TYPO3 Customers
TYPO3 Service
wolfgang weber

Post a Comment

×