From 3f78c6fba4a46d7731fd418e5eaefb152bc838a0 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 27 Sep 2026 09:51:56 +0200 Subject: [PATCH] Document the backward compatibility promise --- doc/backward_compatibility.rst | 99 ++++++++++++++++++++++++++++++++++ doc/deprecated.rst | 4 +- doc/index.rst | 1 + 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 doc/backward_compatibility.rst diff --git a/doc/backward_compatibility.rst b/doc/backward_compatibility.rst new file mode 100644 index 000000000..a8796b83b --- /dev/null +++ b/doc/backward_compatibility.rst @@ -0,0 +1,99 @@ +Backward Compatibility Promise +============================== + +Twig follows `Semantic Versioning`_: upgrading to a new minor or patch release +should be a non-event. Your Twig templates keep rendering the same way, and your +extensions keep working as long as they only use the public API. Features are +only removed in major releases, after being deprecated in a minor one. +Everything else is an implementation detail that can change in any release. + +This page distinguishes two kinds of templates: + +* **Twig templates** are the templates you write in the Twig language, usually + stored in ``.twig`` files. They are covered by the promise; + +* **Compiled templates** are the PHP classes Twig generates from Twig templates + and stores in its cache. They are not covered by the promise. + +Three exceptions apply to the whole promise: + +* **Error messages**: the text of exception and deprecation messages can change + in any release; + +* **Bugs**: a behavior that only works because of a bug can change in any + release. When Twig and its documentation disagree, the documentation is + fixed; Twig is changed instead only when the documentation clearly describes + the intended behavior, which can change the output of Twig templates relying + on the bug; + +* **Security fixes**: backward compatibility can be broken when required to fix + a security issue, for instance in the :doc:`sandbox `. + +Using the Template Language +--------------------------- + +If you write Twig templates, the promise covers the template language: + +* Its syntax: the tags, filters, functions, tests and operators, the arguments + they accept, including their names, and the precedence of operators; + +* The behavior of these features and the output they produce, including how + variables are escaped. + +Extending Twig +-------------- + +If you :doc:`extend Twig `, the promise covers the public API: + +* The classes, interfaces and methods that are not marked as ``@internal``; + +* The documented extension points: extensions, runtimes, filters, functions, + tests, operators, global variables, token parsers, node visitors, loaders, + cache implementations, sandbox security policies and environment options; + +* The node classes that are not marked as ``@internal``: their names, + constructors, attributes and child nodes. A construct of the template + language keeps being represented by the same node class or by a subclass of + it, so ``instanceof`` checks keep working. + +The promise does not cover: + +* **Compiled templates**: their PHP code, including the code any node compiles + to. Compiled templates are also tied to the Twig version that generated them; + +* **The shape of the node tree**: Twig can wrap, add or move nodes, and add + attributes and child nodes to existing node classes. For instance, the + escaper wraps the expression of a ``PrintNode`` in an ``escape`` filter node, + and the sandbox wraps it in a ``CheckToStringNode``. Find nodes with + ``instanceof`` checks while traversing the tree, never at a given place; + +* **Internal code**: classes, methods and properties marked as ``@internal``, + including the ``Twig\Template`` class compiled templates extend and the + methods compiled templates call; + +* **Final classes**: extending a class marked as ``@final``, or listed as + considered final on the :doc:`deprecated features ` page. + +Overriding Built-in Behavior +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Never change what a built-in node compiles to, whether by overriding its +``compile()`` method in a subclass or by changing its attributes, for instance +the callable of a built-in filter. Such code breaks as soon as Twig changes how +the node compiles. Register your own filter, function, test or tag instead. + +Deprecations +------------ + +When a feature of the template language or of the public API is going to be +removed or changed, Twig deprecates it in a minor release: Twig templates and +code using it keep working but trigger a deprecation notice. The feature is +only removed or changed in the next major release, so a Twig template that does +not trigger deprecation notices also works on it. + +The :doc:`deprecated features ` page lists all deprecations with +their replacement, and the :ref:`deprecation notices ` +recipe explains how to find them. Fix them before upgrading to the next major +release. + +.. _`Semantic Versioning`: https://semver.org/ diff --git a/doc/deprecated.rst b/doc/deprecated.rst index 3f7e8b4ba..316a4c025 100644 --- a/doc/deprecated.rst +++ b/doc/deprecated.rst @@ -3,7 +3,9 @@ Deprecated Features This document lists deprecated features in Twig 3.x. Deprecated features are kept for backward compatibility and removed in the next major release (a -feature that was deprecated in Twig 3.x is removed in Twig 4.0). +feature that was deprecated in Twig 3.x is removed in Twig 4.0). Read the +:doc:`backward compatibility promise ` to learn what +minor releases can change. Classes ------- diff --git a/doc/index.rst b/doc/index.rst index 951b2a9ef..972b85614 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -12,6 +12,7 @@ Twig advanced sandbox internals + backward_compatibility deprecated recipes coding_standards