Backwards Compatibility Promise

Everyone involved in the development of Contao knows about the importance of stable software and thus stable APIs. We try our very best to ensure that Contao updates are as smooth as they can be.

Being a project that is built on top of the Symfony full-stack framework, we generally make the same Backwards Compatibility Promise as Symfony itself. We also follow the principles of Semantic Versioning, which means that breaking changes must only be expected when switching to a new major version.

However, in contrast to Symfony, Contao is not “just” a framework. We do not only build the tools for other developers but we also build tools ourselves, which are then shipped with the core distribution of Contao. Therefore, our BC promise deviates from the Symfony BC promise in some regards:

  • Our BC promise does not cover classes and methods marked as @internal. In most cases this concerns constructors of services Contao provides. If you want to change the behaviour of a service, do not replace it with your own instance of the class but instead decorate the original service (see the tip about “Composition over Inheritance”).

  • Our BC promise does not cover classes and methods marked as @experimental. Being able to add experimental code is a great opportunity for us to release new features early without having to worry about the backwards compatibility of the yet unstable API. You’ll find more details in the respective chapter.

  • Our BC promise does not cover templates. Templates are subject to change very often and you have to compare them with every update of Contao. Generally, we try to only ever apply template changes in major and minor versions but if a bugfix requires us to change a template, then we might do that as well.

  • Our BC promise does not cover translation keys. Translations may be added and removed in every minor version as they change quite often. If you want to reuse the labels provided by the core, double check them after every update. You may also provide your own labels, so you are not affected by any changes in the core.

  • Because Contao is a Symfony bundle like every other bundle, our BC promise does not cover anything that is about integrating Contao into the Symfony application. This includes:

    • Commands
    • Data collectors
    • Dependency injection compiler passes
    • Event listeners
  • Our BC promise also does not cover the ContaoManager/Plugin class, which is required to integrate a bundle into the Contao Managed Edition.

  • Our BC promise does not apply to any tests in any bundles. Everything that is meant to facilitate testing in your own extensions and thus can be used is extracted into the contao/test-case package which is versioned according to Semantic Versioning as well.

  • Our BC promise does currently not cover the “Named parameters” introduced in PHP 8.0. You can follow or get involved in the discussion on GitHub.

Composition over Inheritance
The general rule of thumb is that we try to break as little as possible and as much as required. To make sure you are affected as little as possible, you might also benefit from best practices in software engineering such as preferring Composition over Inheritance. Also see how you can decorate a service in Symfony.

If you should encounter a problematic break, please open an issue in our monorepository on GitHub, so we can analyze and discuss if there is a possible solution.