Our Backward Compatibility Promise

Our Backward Compatibility Promise

Ensuring smooth upgrades of your projects is our first priority. That’s why we promise you backward compatibility (BC) for all minor Symfony releases. You probably recognize this strategy as Semantic Versioning. In short, Semantic Versioning means that only major releases (such as 5.0, 6.0 etc.) are allowed to break backward compatibility. Minor releases (such as 5.1, 5.2 etc.) may introduce new features, but must do so without breaking the existing API of that release branch (5.x in the previous example).

We also provide deprecation message triggered in the code base to help you with the migration process across major release.

Caution

This promise was introduced with Symfony 2.3 and does not apply to previous versions of Symfony.

However, backward compatibility comes in many different flavors. In fact, almost every change that we make to the framework can potentially break an application. For example, if we add a new method to a class, this will break an application which extended this class and added the same method, but with a different method signature.

Also, not every BC break has the same impact on application code. While some BC breaks require you to make significant changes to your classes or your architecture, others are fixed by changing the name of a method.

That’s why we created this page for you. The section “Using Symfony Code” will tell you how you can ensure that your application won’t break completely when upgrading to a newer version of the same major release branch.

The second section, “Working on Symfony Code”, is targeted at Symfony contributors. This section lists detailed rules that every contributor needs to follow to ensure smooth upgrades for our users.

Caution

Experimental Features and code marked with the @internal tags are excluded from our Backward Compatibility promise.

Also note that backward compatibility breaks are tolerated if they are required to fix a security issue.

Using Symfony Code

If you are using Symfony in your projects, the following guidelines will help you to ensure smooth upgrades to all future minor releases of your Symfony version.

Using our Interfaces

All interfaces shipped with Symfony can be used in type hints. You can also call any of the methods that they declare. We guarantee that we won’t break code that sticks to these rules.

Caution

The exception to this rule are interfaces tagged with @internal. Such interfaces should not be used or implemented.

If you implement an interface, we promise that we won’t ever break your code.

The following table explains in detail which use cases are covered by our backward compatibility promise:

Use CaseBackward Compatibility
If you…Then we guarantee BC…
Type hint against the interfaceYes
Call a methodYes [10]
If you implement the interface and…Then we guarantee BC…
Implement a methodYes
Add an argument to an implemented methodYes
Add a default value to an argumentYes
Add a return type to an implemented methodYes

Using our Classes

All classes provided by Symfony may be instantiated and accessed through their public methods and properties.

Caution

Classes, properties and methods that bear the tag @internal as well as the classes located in the various *\Tests\ namespaces are an exception to this rule. They are meant for internal use only and should not be accessed by your own code.

To be on the safe side, check the following table to know which use cases are covered by our backward compatibility promise:

Use CaseBackward Compatibility
If you…Then we guarantee BC…
Type hint against the classYes
Create a new instanceYes
Extend the classYes
Access a public propertyYes
Call a public methodYes [10]
If you extend the class and…Then we guarantee BC…
Access a protected propertyYes
Call a protected methodYes [10]
Override a public propertyYes
Override a protected propertyYes
Override a public methodYes
Override a protected methodYes
Add a new propertyNo
Add a new methodNo
Add an argument to an overridden methodYes
Add a default value to an argumentYes
Call a private method (via Reflection)No
Access a private property (via Reflection)No

Using our Traits

All traits provided by Symfony may be used in your classes.

Caution

The exception to this rule are traits tagged with @internal. Such traits should not be used.

To be on the safe side, check the following table to know which use cases are covered by our backward compatibility promise:

Use CaseBackward Compatibility
If you…Then we guarantee BC…
Use a traitYes
If you use the trait and…Then we guarantee BC…
Use it to implement an interfaceYes
Use it to implement an abstract methodYes
Use it to extend a parent classYes
Use it to define an abstract classYes
Use a public, protected or private propertyYes
Use a public, protected or private methodYes

Working on Symfony Code

Do you want to help us improve Symfony? That’s great! However, please stick to the rules listed below in order to ensure smooth upgrades for our users.

Changing Interfaces

This table tells you which changes you are allowed to do when working on Symfony’s interfaces:

Type of ChangeChange Allowed
Remove entirelyNo
Change name or namespaceNo
Add parent interfaceYes [2]
Remove parent interfaceNo
Methods 
Add methodNo
Remove methodNo
Change nameNo
Move to parent interfaceYes
Add argument without a default valueNo
Add argument with a default valueNo
Remove argumentNo [3]
Add default value to an argumentNo
Remove default value of an argumentNo
Add type hint to an argumentNo
Remove type hint of an argumentNo
Change argument typeNo
Add return typeNo
Remove return typeNo [9]
Change return typeNo
Static Methods 
Turn non static into staticNo
Turn static into non staticNo
Constants 
Add constantYes
Remove constantNo
Change value of a constantYes [1] [5]

Changing Classes

This table tells you which changes you are allowed to do when working on Symfony’s classes:

Type of ChangeChange Allowed
Remove entirelyNo
Make finalNo [6]
Make abstractNo
Change name or namespaceNo
Change parent classYes [4]
Add interfaceYes
Remove interfaceNo
Public Properties 
Add public propertyYes
Remove public propertyNo
Reduce visibilityNo
Move to parent classYes
Protected Properties 
Add protected propertyYes
Remove protected propertyNo [7]
Reduce visibilityNo [7]
Make publicNo [7]
Move to parent classYes
Private Properties 
Add private propertyYes
Make public or protectedYes
Remove private propertyYes
Constructors 
Add constructor without mandatory argumentsYes [1]
Remove constructorNo
Reduce visibility of a public constructorNo
Reduce visibility of a protected constructorNo [7]
Move to parent classYes
Destructors 
Add destructorYes
Remove destructorNo
Move to parent classYes
Public Methods 
Add public methodYes
Remove public methodNo
Change nameNo
Reduce visibilityNo
Make finalNo [6]
Move to parent classYes
Add argument without a default valueNo
Add argument with a default valueNo [7] [8]
Remove argumentNo [3]
Add default value to an argumentNo [7] [8]
Remove default value of an argumentNo
Add type hint to an argumentNo [7] [8]
Remove type hint of an argumentNo [7] [8]
Change argument typeNo [7] [8]
Add return typeNo [7] [8]
Remove return typeNo [7] [8] [9]
Change return typeNo [7] [8]
Protected Methods 
Add protected methodYes
Remove protected methodNo [7]
Change nameNo [7]
Reduce visibilityNo [7]
Make finalNo [6]
Make publicNo [7] [8]
Move to parent classYes
Add argument without a default valueNo [7]
Add argument with a default valueNo [7] [8]
Remove argumentNo [3]
Add default value to an argumentNo [7] [8]
Remove default value of an argumentNo [7]
Add type hint to an argumentNo [7] [8]
Remove type hint of an argumentNo [7] [8]
Change argument typeNo [7] [8]
Add return typeNo [7] [8]
Remove return typeNo [7] [8] [9]
Change return typeNo [7] [8]
Private Methods 
Add private methodYes
Remove private methodYes
Change nameYes
Make public or protectedYes
Add argument without a default valueYes
Add argument with a default valueYes
Remove argumentYes
Add default value to an argumentYes
Remove default value of an argumentYes
Add type hint to an argumentYes
Remove type hint of an argumentYes
Change argument typeYes
Add return typeYes
Remove return typeYes
Change return typeYes
Static Methods and Properties 
Turn non static into staticNo [7] [8]
Turn static into non staticNo
Constants 
Add constantYes
Remove constantNo
Change value of a constantYes [1] [5]

Changing Traits

This table tells you which changes you are allowed to do when working on Symfony’s traits:

Type of ChangeChange Allowed
Remove entirelyNo
Change name or namespaceNo
Use another traitYes
Public Properties 
Add public propertyYes
Remove public propertyNo
Reduce visibilityNo
Move to a used traitYes
Protected Properties 
Add protected propertyYes
Remove protected propertyNo
Reduce visibilityNo
Make publicNo
Move to a used traitYes
Private Properties 
Add private propertyYes
Remove private propertyNo
Make public or protectedYes
Move to a used traitYes
Constructors and destructors 
Have constructor or destructorNo
Public Methods 
Add public methodYes
Remove public methodNo
Change nameNo
Reduce visibilityNo
Make finalNo [6]
Move to used traitYes
Add argument without a default valueNo
Add argument with a default valueNo
Remove argumentNo
Add default value to an argumentNo
Remove default value of an argumentNo
Add type hint to an argumentNo
Remove type hint of an argumentNo
Change argument typeNo
Change return typeNo
Protected Methods 
Add protected methodYes
Remove protected methodNo
Change nameNo
Reduce visibilityNo
Make finalNo [6]
Make publicNo [8]
Move to used traitYes
Add argument without a default valueNo
Add argument with a default valueNo
Remove argumentNo
Add default value to an argumentNo
Remove default value of an argumentNo
Add type hint to an argumentNo
Remove type hint of an argumentNo
Change argument typeNo
Change return typeNo
Private Methods 
Add private methodYes
Remove private methodNo
Change nameNo
Make public or protectedYes
Move to used traitYes
Add argument without a default valueNo
Add argument with a default valueNo
Remove argumentNo
Add default value to an argumentNo
Remove default value of an argumentNo
Add type hint to an argumentNo
Remove type hint of an argumentNo
Change argument typeNo
Add return typeNo
Remove return typeNo
Change return typeNo
Static Methods and Properties 
Turn non static into staticNo
Turn static into non staticNo
[1](1, 2, 3) Should be avoided. When done, this change must be documented in the UPGRADE file.
[2]The added parent interface must not introduce any new methods that don’t exist in the interface already.
[3](1, 2, 3) Only the last optional argument(s) of a method may be removed, as PHP does not care about additional arguments that you pass to a method.
[4]When changing the parent class, the original parent class must remain an ancestor of the class.
[5](1, 2) The value of a constant may only be changed when the constants aren’t used in configuration (e.g. Yaml and XML files), as these do not support constants and have to hardcode the value. For instance, event name constants can’t change the value without introducing a BC break. Additionally, if a constant will likely be used in objects that are serialized, the value of a constant should not be changed.
[6](1, 2, 3, 4, 5) Allowed using the @final annotation.
[7](1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27) Allowed if the class is final. Classes that received the @final annotation after their first release are considered final in their next major version. Changing an argument type is only possible with a parent type. Changing a return type is only possible with a child type.
[8](1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) Allowed if the method is final. Methods that received the @final annotation after their first release are considered final in their next major version. Changing an argument type is only possible with a parent type. Changing a return type is only possible with a child type.
[9](1, 2, 3) Allowed for the void return type.
[10](1, 2, 3) Parameter names are not part of the compatibility promise. Using PHP 8’s named arguments feature might break your code when upgrading to newer Symfony versions.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.