Migration steps

Delete files

Yes, that's true. You have to delete some files, because they will be created by Composer in some of the next steps.

You have to delete, public/index.php, public/typo3/ and all the extensions inside public/typo3conf/ext/, you downloaded from TER or any other resources like GitHub. You even have to delete your own extensions, if they are available in a separate Git repository and, for example, included as Git submodule.

Please keep only your sitepackage extension or any other extension, which was explicitly built for your current project and does not have an own Git repository.

Configure composer

Create a file with name composer.json in your project root, not inside your web root.

You can use the composer.json from typo3/cms-base-distribution as an example. Use the file from the branch which matches your current version, for example 11.x.

However, this may require extensions you don't need or omit extensions you do need, so be sure to update the required extensions as described in the next sections.

The composer.json in the Base distribution includes a scripts section:

/composer.json
{
   "scripts": {
      "typo3-cms-scripts": [
         "typo3cms install:generatepackagestates",
         "typo3cms install:fixfolderstructure"
      ],
      "post-autoload-dump": [
         "@typo3-cms-scripts"
      ]
   }
}
Copied!

This requires helhum/typo3-console (so be sure to require that too) and is essential for generating the file typo3conf/PackageStates.php.

Add all required packages to your project

You can add all your required packages with the Composer command composer require. The full syntax is:

typo3_root$
composer require anyvendorname/anypackagename:version
Copied!

Example:

typo3_root$
composer require typo3/minimal:^9.5
Copied!

There are different ways to define the version of the package, you want to install. The most common syntaxes start with ^ (e.g. ^9.5) or with ~ (e.g. ~9.5.0). A full documentation can be found at https://getcomposer.org/doc/articles/versions.md

In short:

  • ^9.5 or ^9.5.0 tells Composer to add newest package of version 9.* with at least 9.5.0, but not version 10.
  • ~9.5.0 tells composer to add the newest package of version 9.5.* with at least 9.5.0, but not version 9.6.

You have to decide by yourself, which syntax fits best to your needs.

Install the Core

Install the system extensions:

typo3_root$
composer require typo3/minimal:^9.5
composer require typo3/cms-scheduler:^9.5
composer require ...
Copied!

Or in one line:

typo3_root$
composer require typo3/cms-minimal:^9.5 typo3/cms-scheduler:^9.5 ...
Copied!

To find the correct package names, you can either take a look in the composer.json of any system extension or follow the naming convention typo3/cms-<extension name with dash "-" instead of underscore "_">, e.g. typo3/cms-fluid-styled-content.

Install extensions from packagist

You already know the TER and always used it to install extensions? Fine. But with Composer, the preferred way is to install extensions directly from packagist.org. This works great, when the maintainer uploaded them to there. Many well known extensions are already available. You only need to known the package name. There are multiple ways to find it:

Notice on extension's TER page

Extension maintainers optionally can link their TYPO3 extension in TER with the correct Composer key on packagist.org. Some maintainers already did that and if you search the extension in TER, you will see a message, which command and Composer key you can use to install this extension.

Check manually

This is the most exhausting way. But it will work, even if the extension maintainer does not provide additional information.

  1. Search and open the extension, you want to install, in TER.
  2. Click button "Take a look into the code".

  3. Open file composer.json.

  4. Search for line with property "name", it's value should be formatted like vendor/package.

  5. Check, if the package can be found on packagist.org.

Example: To install the mask extension in version 4.1.*, type:

typo3_root$
composer require mask/mask:~4.1.0
Copied!

Install extension from version control system (e.g. GitHub, Gitlab, ...)

In some cases, you will have to install a TYPO3 extension, which is not available on packagist.org or in the TER. Examples could be:

  • non-public extension only used by your company.
  • you forked and modified an existing extension.

As first step, you have to define the repository in your composer.json's "repositories" section. In this example, you find the additional lines added to the composer.json from above:

/composer.json
{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/foo/bar.git"
        }
    ],
    "extra": {
        "typo3/cms": {
            "web-dir": "public"
        }
    }
}
Copied!

The Git repository must be a TYPO3 extension with a composer.json itself. How this file should look in your extension, can be found on this blog post from Helmut Hummel. Please note, that Git tags are used as version numbers.

If you fulfill these requirements, you can add your extension in the same way like the other examples:

typo3_root$
composer require foo/bar:~1.0.0
Copied!

Include individual extensions like site packages

It's not necessary to move your project's site package to a dedicated Git repository to re-include it in your project. You can keep the files in your main project (e.g. public/typo3conf/ext/my_sitepackage). There is only one thing to do; Because TYPO3's autoload feature works differently in Composer based installations, you have to register your PHP class names in Composer. This is very easy when you use PHP namespaces:

EXT:my_sitepackage/composer.json
{
     "autoload": {
         "psr-4": {
             "VendorName\\MySitepackage\\": "public/typo3conf/ext/my_sitepackage/Classes/",
             "VendorName\\AnyOtherExtension\\": "public/typo3conf/ext/any_other_extension/Classes/"
         }
     }
}
Copied!

For extension without PHP namespaces, this section has to look a bit differently. You can decide by yourself, if you want to list each PHP file manually or if Composer should search for them inside a folder:

EXT:my_sitepackage/composer.json
{
     "autoload": {
         "classmap": [
             "public/typo3conf/ext/my_old_extension/pi1/",
             "public/typo3conf/ext/my_old_extension/pi2/class.tx_myoldextension_pi2.php"
         ]
     }
}
Copied!

To complete our example composer.json, it would look like this:

typo3_root/composer.json
{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/foo/bar.git"
        }
    ],
    "extra": {
        "typo3/cms": {
            "web-dir": "public"
        }
    },
    "autoload": {
        "psr-4": {
            "VendorName\\MySitepackage\\": "public/typo3conf/ext/my_sitepackage/Classes/",
            "VendorName\\AnyOtherExtension\\": "public/typo3conf/ext/any_other_extension/Classes/"
        },
        "classmap": [
            "public/typo3conf/ext/my_old_extension/pi1/",
            "public/typo3conf/ext/my_old_extension/pi2/class.tx_myoldextension_pi2.php"
        ]
    }
}
Copied!

After adding paths to the autoload you should run composer dumpautoload. This command will re-generate the autoload info and should be run anytime you add new paths to the autoload portion in the composer.json.

New file locations

As final steps, you should move some files because the location will have changed for your site since moving to Composer.

You should at least move the site configuration and the translations.

Move files:

typo3_root$
mv public/typo3conf/sites config/sites
mv public/typo3temp/var var
mv public/typo3conf/l10n var/labels
Copied!

These locations have changed:

Before After
public/typo3conf/sites config/sites
public/typo3temp/var var
public/typo3conf/l10n var/labels

Have a look at Directory structure in "TYPO3 Explained". As developer, you should also be familiar with the Environment API.

These file locations have not changed:

public/typo3conf/LocalConfiguration.php
public/typo3conf/AdditionalConfiguration.php
public/typo3conf/PackageStates.php
public/typo3conf/ext

This means, the config directory does not exactly replace the public/typo3conf directory. This may change in the future.