diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml
index 5c3d2fd7687..dfb85021586 100644
--- a/.doctor-rst.yaml
+++ b/.doctor-rst.yaml
@@ -75,16 +75,16 @@ rules:
     yaml_instead_of_yml_suffix: ~
 
     versionadded_directive_major_version:
-        major_version: 6
+        major_version: 7
 
     versionadded_directive_min_version:
-        min_version: '6.0'
+        min_version: '7.0'
 
     deprecated_directive_major_version:
-        major_version: 6
+        major_version: 7
 
     deprecated_directive_min_version:
-        min_version: '6.0'
+        min_version: '7.0'
 
 exclude_rule_for_file:
     - path: configuration/multiple_kernels.rst
diff --git a/_build/build.php b/_build/build.php
index b80d8e0e51e..b684700a848 100755
--- a/_build/build.php
+++ b/_build/build.php
@@ -27,7 +27,7 @@
 
         $outputDir = __DIR__.'/output';
         $buildConfig = (new BuildConfig())
-            ->setSymfonyVersion('6.4')
+            ->setSymfonyVersion('7.1')
             ->setContentDir(__DIR__.'/..')
             ->setOutputDir($outputDir)
             ->setImagesDir(__DIR__.'/output/_images')
diff --git a/_build/redirection_map b/_build/redirection_map
index 995ea20f4cc..c30723eac58 100644
--- a/_build/redirection_map
+++ b/_build/redirection_map
@@ -530,7 +530,7 @@
 /serializer/normalizers /serializer#serializer-built-in-normalizers
 /logging/monolog_regex_based_excludes /logging/monolog_exclude_http_codes
 /security/named_encoders /security/named_hashers
-/components/inflector /components/string#inflector
+/components/inflector /string#inflector
 /security/experimental_authenticators /security
 /security/user_provider /security/user_providers
 /security/reset_password /security/passwords#reset-password
@@ -568,8 +568,14 @@
 /messenger/dispatch_after_current_bus /messenger#messenger-transactional-messages
 /messenger/multiple_buses /messenger#messenger-multiple-buses
 /frontend/encore/server-data /frontend/server-data
+/components/string /string
+/testing/http_authentication /testing#testing_logging_in_users
+/doctrine/registration_form /security#security-make-registration-form
+/form/form_dependencies /form/create_custom_field_type
+/doctrine/reverse_engineering /doctrine#doctrine-adding-mapping
 /components/serializer /serializer
 /serializer/custom_encoder /serializer/encoders#serializer-custom-encoder
+/components/string /string
 /form/button_based_validation /form/validation_groups
 /form/data_based_validation /form/validation_groups
 /form/validation_group_service_resolver /form/validation_groups
diff --git a/_includes/_annotation_loader_tip.rst.inc b/_includes/_annotation_loader_tip.rst.inc
deleted file mode 100644
index 0f4267b07f5..00000000000
--- a/_includes/_annotation_loader_tip.rst.inc
+++ /dev/null
@@ -1,19 +0,0 @@
-.. note::
-
-    In order to use the annotation loader, you should have installed the
-    ``doctrine/annotations`` and ``doctrine/cache`` packages with Composer.
-
-.. tip::
-
-    Annotation classes aren't loaded automatically, so you must load them
-    using a class loader like this::
-
-        use Composer\Autoload\ClassLoader;
-        use Doctrine\Common\Annotations\AnnotationRegistry;
-
-        /** @var ClassLoader $loader */
-        $loader = require __DIR__.'/../vendor/autoload.php';
-
-        AnnotationRegistry::registerLoader([$loader, 'loadClass']);
-
-        return $loader;
diff --git a/bundles.rst b/bundles.rst
index 93a9ceafc0e..3e590a4e2aa 100644
--- a/bundles.rst
+++ b/bundles.rst
@@ -58,11 +58,6 @@ Start by creating a new class called ``AcmeBlogBundle``::
     {
     }
 
-.. versionadded:: 6.1
-
-    The :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle` was
-    introduced in Symfony 6.1.
-
 .. warning::
 
     If your bundle must be compatible with previous Symfony versions you have to
diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst
index 99d254b7929..8049ebb9a1c 100644
--- a/bundles/best_practices.rst
+++ b/bundles/best_practices.rst
@@ -232,10 +232,10 @@ with Symfony Flex to install a specific Symfony version:
 
 .. code-block:: bash
 
-    # this requires Symfony 6.x for all Symfony packages
-    export SYMFONY_REQUIRE=6.*
+    # this requires Symfony 7.x for all Symfony packages
+    export SYMFONY_REQUIRE=7.*
     # alternatively you can run this command to update composer.json config
-    # composer config extra.symfony.require "6.*"
+    # composer config extra.symfony.require "7.*"
 
     # install Symfony Flex in the CI environment
     composer global config --no-plugins allow-plugins.symfony/flex true
diff --git a/bundles/configuration.rst b/bundles/configuration.rst
index ab15675105f..dedfada2ea2 100644
--- a/bundles/configuration.rst
+++ b/bundles/configuration.rst
@@ -61,10 +61,6 @@ There are two different ways of creating friendly configuration for a bundle:
 Using the AbstractBundle Class
 ------------------------------
 
-.. versionadded:: 6.1
-
-    The ``AbstractBundle`` class was introduced in Symfony 6.1.
-
 In bundles extending the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
 class, you can add all the logic related to processing the configuration in that class::
 
diff --git a/bundles/extension.rst b/bundles/extension.rst
index 607ca1404fb..d2792efc477 100644
--- a/bundles/extension.rst
+++ b/bundles/extension.rst
@@ -20,10 +20,6 @@ There are two different ways of doing it:
 Loading Services Directly in your Bundle Class
 ----------------------------------------------
 
-.. versionadded:: 6.1
-
-    The ``AbstractBundle`` class was introduced in Symfony 6.1.
-
 In bundles extending the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
 class, you can define the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::loadExtension`
 method to load service definitions from configuration files::
diff --git a/bundles/prepend_extension.rst b/bundles/prepend_extension.rst
index afde2595e98..e4099d9f81a 100644
--- a/bundles/prepend_extension.rst
+++ b/bundles/prepend_extension.rst
@@ -154,10 +154,6 @@ registered and the ``entity_manager_name`` setting for ``acme_hello`` is set to
 Prepending Extension in the Bundle Class
 ----------------------------------------
 
-.. versionadded:: 6.1
-
-    The ``AbstractBundle`` class was introduced in Symfony 6.1.
-
 You can also prepend extension configuration directly in your
 Bundle class if you extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
 class and define the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::prependExtension`
@@ -175,6 +171,9 @@ method::
             $containerBuilder->prependExtensionConfig('framework', [
                 'cache' => ['prefix_seed' => 'foo/bar'],
             ]);
+
+            // prepend config from a file
+            $containerConfigurator->import('../config/packages/cache.php');
         }
     }
 
@@ -182,6 +181,40 @@ method::
 
     The ``prependExtension()`` method, like ``prepend()``, is called only at compile time.
 
+.. versionadded:: 7.1
+
+    Starting from Symfony 7.1, calling the :method:`Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator::import`
+    method inside ``prependExtension()`` will prepend the given configuration.
+    In previous Symfony versions, this method appended the configuration.
+
+Alternatively, you can use the ``prepend`` parameter of the
+:method:`Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator::extension`
+method::
+
+    use Symfony\Component\DependencyInjection\ContainerBuilder;
+    use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+    use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
+
+    class FooBundle extends AbstractBundle
+    {
+        public function prependExtension(ContainerConfigurator $containerConfigurator, ContainerBuilder $containerBuilder): void
+        {
+            // ...
+
+            $containerConfigurator->extension('framework', [
+                'cache' => ['prefix_seed' => 'foo/bar'],
+            ], prepend: true);
+
+            // ...
+        }
+    }
+
+.. versionadded:: 7.1
+
+    The ``prepend`` parameter of the
+    :method:`Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ContainerConfigurator::extension`
+    method was added in Symfony 7.1.
+
 More than one Bundle using PrependExtensionInterface
 ----------------------------------------------------
 
diff --git a/cache.rst b/cache.rst
index 71fe56c2b33..9379511fde8 100644
--- a/cache.rst
+++ b/cache.rst
@@ -132,12 +132,7 @@ Some of these adapters could be configured via shortcuts.
                 default_psr6_provider: 'app.my_psr6_service'
                 default_redis_provider: 'redis://localhost'
                 default_memcached_provider: 'memcached://localhost'
-                default_pdo_provider: 'app.my_pdo_service'
-
-        services:
-            app.my_pdo_service:
-                class: \PDO
-                arguments: ['pgsql:host=localhost']
+                default_pdo_provider: 'pgsql:host=localhost'
 
     .. code-block:: xml
 
@@ -158,24 +153,17 @@ Some of these adapters could be configured via shortcuts.
                     default-psr6-provider="app.my_psr6_service"
                     default-redis-provider="redis://localhost"
                     default-memcached-provider="memcached://localhost"
-                    default-pdo-provider="app.my_pdo_service"
+                    default-pdo-provider="pgsql:host=localhost"
                 />
             </framework:config>
-
-            <services>
-                <service id="app.my_pdo_service" class="\PDO">
-                    <argument>pgsql:host=localhost</argument>
-                </service>
-            </services>
         </container>
 
     .. code-block:: php
 
         // config/packages/cache.php
-        use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
         use Symfony\Config\FrameworkConfig;
 
-        return static function (FrameworkConfig $framework, ContainerConfigurator $container): void {
+        return static function (FrameworkConfig $framework): void {
             $framework->cache()
                 // Only used with cache.adapter.filesystem
                 ->directory('%kernel.cache_dir%/pools')
@@ -184,15 +172,14 @@ Some of these adapters could be configured via shortcuts.
                 ->defaultPsr6Provider('app.my_psr6_service')
                 ->defaultRedisProvider('redis://localhost')
                 ->defaultMemcachedProvider('memcached://localhost')
-                ->defaultPdoProvider('app.my_pdo_service')
-            ;
-
-            $container->services()
-                ->set('app.my_pdo_service', \PDO::class)
-                ->args(['pgsql:host=localhost'])
+                ->defaultPdoProvider('pgsql:host=localhost')
             ;
         };
 
+.. versionadded:: 7.1
+
+    Using a DSN as the provider for the PDO adapter was introduced in Symfony 7.1.
+
 .. _cache-create-pools:
 
 Creating Custom (Namespaced) Pools
@@ -551,6 +538,8 @@ Symfony stores the item automatically in all the missing pools.
             ;
         };
 
+.. _cache-using-cache-tags:
+
 Using Cache Tags
 ----------------
 
@@ -743,20 +732,12 @@ Clear all cache pools:
 
     $ php bin/console cache:pool:clear --all
 
-.. versionadded:: 6.3
-
-    The ``--all`` option was introduced in Symfony 6.3.
-
 Clear all cache pools except some:
 
 .. code-block:: terminal
 
     $ php bin/console cache:pool:clear --all --exclude=my_cache_pool --exclude=another_cache_pool
 
-.. versionadded:: 6.4
-
-    The ``--exclude`` option was introduced in Symfony 6.4.
-
 Clear all caches everywhere:
 
 .. code-block:: terminal
@@ -765,10 +746,6 @@ Clear all caches everywhere:
 
 Clear cache by tag(s):
 
-.. versionadded:: 6.1
-
-    The ``cache:pool:invalidate-tags`` command was introduced in Symfony 6.1.
-
 .. code-block:: terminal
 
     # invalidate tag1 from all taggable pools
diff --git a/components/browser_kit.rst b/components/browser_kit.rst
index 21ceaf5a095..8cf0772298c 100644
--- a/components/browser_kit.rst
+++ b/components/browser_kit.rst
@@ -130,10 +130,6 @@ on a link::
     // ... and `clickLink()`
     $crawler = $client->clickLink('Go elsewhere...', ['X-Custom-Header' => 'Some data']);
 
-.. versionadded:: 6.4
-
-    The ``serverParameters`` parameter was introduced in Symfony 6.4.
-
 Submitting Forms
 ~~~~~~~~~~~~~~~~
 
@@ -403,10 +399,6 @@ to call ``json_decode()`` explicitly::
     $response = $browser->getResponse()->toArray();
     // $response is a PHP array of the decoded JSON contents
 
-.. versionadded:: 6.1
-
-    The ``toArray()`` method was introduced in Symfony 6.1.
-
 Learn more
 ----------
 
diff --git a/components/cache.rst b/components/cache.rst
index f5a76f2119d..44ba8b5c151 100644
--- a/components/cache.rst
+++ b/components/cache.rst
@@ -84,6 +84,69 @@ generate and return the value::
     Use cache tags to delete more than one key at the time. Read more at
     :doc:`/components/cache/cache_invalidation`.
 
+Creating Sub-Namespaces
+-----------------------
+
+.. versionadded:: 7.3
+
+   Cache sub-namespaces were introduced in Symfony 7.3.
+
+Sometimes you need to create context-dependent variations of data that should be
+cached. For example, the data used to render a dashboard page may be expensive
+to generate and unique per user, so you can't cache the same data for everyone.
+
+In such cases, Symfony allows you to create different cache contexts using
+namespaces. A cache namespace is an arbitrary string that identifies a set of
+related cache items. All cache adapters provided by the component implement the
+:class:`Symfony\\Contracts\\Cache\\NamespacedPoolInterface`, which provides the
+:method:`Symfony\\Contracts\\Cache\\NamespacedPoolInterface::withSubNamespace`
+method.
+
+This method allows you to namespace cached items by transparently prefixing their keys::
+
+    $userCache = $cache->withSubNamespace(sprintf('user-%d', $user->getId()));
+
+    $userCache->get('dashboard_data', function (ItemInterface $item): string {
+        $item->expiresAfter(3600);
+
+        return '...';
+    });
+
+In this example, the cache item uses the ``dashboard_data`` key, but it will be
+stored internally under a namespace based on the current user ID. This is handled
+automatically, so you **don't** need to manually prefix keys like ``user-27.dashboard_data``.
+
+There are no guidelines or restrictions on how to define cache namespaces.
+You can make them as granular or as generic as your application requires::
+
+    $localeCache = $cache->withSubNamespace($request->getLocale());
+
+    $flagCache = $cache->withSubNamespace(
+        $featureToggle->isEnabled('new_checkout') ? 'checkout-v2' : 'checkout-v1'
+    );
+
+    $channel = $request->attributes->get('_route')?->startsWith('api_') ? 'api' : 'web';
+    $channelCache = $cache->withSubNamespace($channel);
+
+.. tip::
+
+    You can combine cache namespaces with :ref:`cache tags <cache-using-cache-tags>`
+    for more advanced needs.
+
+There is no built-in way to invalidate caches by namespace. Instead, the recommended
+approach is to change the namespace itself. For this reason, it's common to include
+static or dynamic versioning data in the cache namespace::
+
+    // for simple applications, an incrementing static version number may be enough
+    $userCache = $cache->withSubNamespace(sprintf('v1-user-%d', $user->getId()));
+
+    // other applications may use dynamic versioning based on the date (e.g. monthly)
+    $userCache = $cache->withSubNamespace(sprintf('%s-user-%d', date('Ym'), $user->getId()));
+
+    // or even invalidate the cache when the user data changes
+    $checksum = hash('xxh128', $user->getUpdatedAt()->format(DATE_ATOM));
+    $userCache = $cache->withSubNamespace(sprintf('user-%d-%s', $user->getId(), $checksum));
+
 .. _cache_stampede-prevention:
 
 Stampede Prevention
@@ -208,16 +271,27 @@ Symfony uses *marshallers* (classes which implement
 the cache items before storing them.
 
 The :class:`Symfony\\Component\\Cache\\Marshaller\\DefaultMarshaller` uses PHP's
-``serialize()`` or ``igbinary_serialize()`` if the `Igbinary extension`_ is installed.
-There are other *marshallers* that can encrypt or compress the data before storing it::
+``serialize()`` function by default, but you can optionally use the ``igbinary_serialize()``
+function from the `Igbinary extension`_::
 
     use Symfony\Component\Cache\Adapter\RedisAdapter;
-    use Symfony\Component\Cache\DefaultMarshaller;
-    use Symfony\Component\Cache\DeflateMarshaller;
+    use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
+    use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
 
     $marshaller = new DeflateMarshaller(new DefaultMarshaller());
+    // you can optionally use the Igbinary extension if you have it installed
+    // $marshaller = new DeflateMarshaller(new DefaultMarshaller(useIgbinarySerialize: true));
+
     $cache = new RedisAdapter(new \Redis(), 'namespace', 0, $marshaller);
 
+There are other *marshallers* that can encrypt or compress the data before storing it.
+
+.. versionadded:: 7.2
+
+    In Symfony versions prior to 7.2, the ``igbinary_serialize()`` function was
+    used by default when the Igbinary extension was installed. Starting from
+    Symfony 7.2, you have to enable Igbinary support explicitly.
+
 Advanced Usage
 --------------
 
diff --git a/components/cache/adapters/array_cache_adapter.rst b/components/cache/adapters/array_cache_adapter.rst
index f903771e468..08f8276db3d 100644
--- a/components/cache/adapters/array_cache_adapter.rst
+++ b/components/cache/adapters/array_cache_adapter.rst
@@ -24,5 +24,14 @@ method::
 
         // the maximum number of items that can be stored in the cache. When the limit
         // is reached, cache follows the LRU model (least recently used items are deleted)
-        $maxItems = 0
+        $maxItems = 0,
+
+        // optional implementation of the Psr\Clock\ClockInterface that will be used
+        // to calculate the lifetime of cache items (for example to get predictable
+        // lifetimes in tests)
+        $clock = null,
     );
+
+.. versionadded:: 7.2
+
+    The optional ``$clock`` argument was introduced in Symfony 7.2.
diff --git a/components/cache/adapters/couchbasebucket_adapter.rst b/components/cache/adapters/couchbasebucket_adapter.rst
index 970dabe2cd9..29c9e26f83c 100644
--- a/components/cache/adapters/couchbasebucket_adapter.rst
+++ b/components/cache/adapters/couchbasebucket_adapter.rst
@@ -1,6 +1,12 @@
 Couchbase Bucket Cache Adapter
 ==============================
 
+.. deprecated:: 7.1
+
+    The ``CouchbaseBucketAdapter`` is deprecated since Symfony 7.1, use the
+    :doc:`CouchbaseCollectionAdapter </components/cache/adapters/couchbasecollection_adapter>`
+    instead.
+
 This adapter stores the values in-memory using one (or more) `Couchbase server`_
 instances. Unlike the :doc:`APCu adapter </components/cache/adapters/apcu_adapter>`, and similarly to the
 :doc:`Memcached adapter </components/cache/adapters/memcached_adapter>`, it is not limited to the current server's
diff --git a/components/cache/adapters/doctrine_dbal_adapter.rst b/components/cache/adapters/doctrine_dbal_adapter.rst
index fc04410bffc..68732ddd3fa 100644
--- a/components/cache/adapters/doctrine_dbal_adapter.rst
+++ b/components/cache/adapters/doctrine_dbal_adapter.rst
@@ -39,5 +39,22 @@ optional arguments::
     necessary to detect the database engine and version without opening the
     connection.
 
+The adapter uses SQL syntax that is optimized for database server that it is connected to.
+The following database servers are known to be compatible:
+
+* MySQL 5.7 and newer
+* MariaDB 10.2 and newer
+* Oracle 10g and newer
+* SQL Server 2012 and newer
+* SQLite 3.24 or later
+* PostgreSQL 9.5 or later
+
+.. note::
+
+    Newer releases of Doctrine DBAL might increase these minimal versions. Check
+    the manual page on `Doctrine DBAL Platforms`_ if your database server is
+    compatible with the installed Doctrine DBAL version.
+
 .. _`Doctrine DBAL Connection`: https://github.com/doctrine/dbal/blob/master/src/Connection.php
-.. _`Doctrine DBAL URL`: https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
+.. _`Doctrine DBAL URL`: https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/configuration.html#connecting-using-a-url
+.. _`Doctrine DBAL Platforms`: https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/platforms.html
diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst
index 503fc42454d..c0295b487a0 100644
--- a/components/cache/adapters/redis_adapter.rst
+++ b/components/cache/adapters/redis_adapter.rst
@@ -8,7 +8,8 @@ Redis Cache Adapter
     :ref:`Symfony Cache configuration <cache-configuration-with-frameworkbundle>`
     article if you are using it in a Symfony application.
 
-This adapter stores the values in-memory using one (or more) `Redis server`_ instances.
+This adapter stores the values in-memory using one (or more) `Redis server`_
+of `Valkey`_ server instances.
 
 Unlike the :doc:`APCu adapter </components/cache/adapters/apcu_adapter>`, and similarly to the
 :doc:`Memcached adapter </components/cache/adapters/memcached_adapter>`, it is not limited to the current server's
@@ -19,9 +20,9 @@ to utilize a cluster of servers to provide redundancy and/or fail-over is also a
 
     **Requirements:** At least one `Redis server`_ must be installed and running to use this
     adapter. Additionally, this adapter requires a compatible extension or library that implements
-    ``\Redis``, ``\RedisArray``, ``RedisCluster``, ``\Relay\Relay`` or ``\Predis``.
+    ``\Redis``, ``\RedisArray``, ``RedisCluster``, ``\Relay\Relay``, ``\Relay\Cluster`` or ``\Predis``.
 
-This adapter expects a `Redis`_, `RedisArray`_, `RedisCluster`_, `Relay`_ or `Predis`_ instance to be
+This adapter expects a `Redis`_, `RedisArray`_, `RedisCluster`_, `Relay`_, `RelayCluster`_ or `Predis`_ instance to be
 passed as the first parameter. A namespace and default cache lifetime can optionally be passed
 as the second and third parameters::
 
@@ -47,9 +48,9 @@ as the second and third parameters::
         ?MarshallerInterface $marshaller = null
     );
 
-.. versionadded:: 6.3
+.. versionadded:: 7.3
 
-    Support for `Relay`_ was introduced in Symfony 6.3.
+    Support for ``Relay\Cluster`` was introduced in Symfony 7.3.
 
 Configure the Connection
 ------------------------
@@ -65,6 +66,11 @@ helper method allows creating and configuring the Redis client class instance us
         'redis://localhost'
     );
 
+.. versionadded:: 7.3
+
+    Starting in Symfony 7.3, when using Valkey servers you can use the
+    ``valkey[s]:`` scheme instead of the ``redis[s]:`` one in your DSNs.
+
 The DSN can specify either an IP/host (and an optional port) or a socket path, as well as a
 password and a database index. To enable TLS for connections, the scheme ``redis`` must be
 replaced by ``rediss`` (the second ``s`` means "secure").
@@ -169,10 +175,6 @@ array of ``key => value`` pairs representing option names and their respective v
 Available Options
 ~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    ``\Relay\Relay`` support was introduced in Symfony 6.3.
-
 ``class`` (type: ``string``, default: ``null``)
     Specifies the connection library to return, either ``\Redis``, ``\Relay\Relay`` or ``\Predis\Client``.
     If none is specified, fallback value is in following order, depending which one is available first:
@@ -214,6 +216,9 @@ Available Options
 ``redis_sentinel`` (type: ``string``, default: ``null``)
     Specifies the master name connected to the sentinels.
 
+``sentinel_master`` (type: ``string``, default: ``null``)
+    Alias of ``redis_sentinel`` option.
+
 ``dbindex`` (type: ``int``, default: ``0``)
     Specifies the database index to select.
 
@@ -225,6 +230,34 @@ Available Options
 ``ssl`` (type: ``array``, default: ``null``)
     SSL context options. See `php.net/context.ssl`_ for more information.
 
+``relay_cluster_context`` (type: ``array``, default: ``[]``)
+    Defines configuration options specific to ``\Relay\Cluster``. For example, to
+    user a self-signed certificate for testing in local environment::
+
+        $options = [
+            // ...
+            'relay_cluster_context' => [
+                // ...
+                'stream' => [
+                    'verify_peer' => false,
+                    'verify_peer_name' => false,
+                    'allow_self_signed' => true,
+                    'local_cert' => '/valkey.crt',
+                    'local_pk' => '/valkey.key',
+                    'cafile' => '/valkey.crt',
+                ],
+            ],
+        ];
+
+.. versionadded:: 7.1
+
+    The option ``sentinel_master`` as an alias for ``redis_sentinel`` was introduced
+    in Symfony 7.1.
+
+.. versionadded:: 7.3
+
+    The ``relay_cluster_context`` option was introduced in Symfony 7.3.
+
 .. note::
 
     When using the `Predis`_ library some additional Predis-specific options are available.
@@ -348,10 +381,12 @@ Supports key rotation, ensuring secure decryption with both old and new keys::
 
 .. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name
 .. _`Redis server`: https://redis.io/
+.. _`Valkey`: https://valkey.io/
 .. _`Redis`: https://github.com/phpredis/phpredis
 .. _`RedisArray`: https://github.com/phpredis/phpredis/blob/develop/arrays.md
 .. _`RedisCluster`: https://github.com/phpredis/phpredis/blob/develop/cluster.md
 .. _`Relay`: https://relay.so/
+.. _`RelayCluster`: https://relay.so/docs/1.x/connections#cluster
 .. _`Predis`: https://packagist.org/packages/predis/predis
 .. _`Predis Connection Parameters`: https://github.com/nrk/predis/wiki/Connection-Parameters#list-of-connection-parameters
 .. _`TCP-keepalive`: https://redis.io/topics/clients#tcp-keepalive
diff --git a/components/clock.rst b/components/clock.rst
index 1ae56775b77..c4ac88e9092 100644
--- a/components/clock.rst
+++ b/components/clock.rst
@@ -1,10 +1,6 @@
 The Clock Component
 ===================
 
-.. versionadded:: 6.2
-
-    The Clock component was introduced in Symfony 6.2
-
 The Clock component decouples applications from the system clock. This allows
 you to fix time to improve testability of time-sensitive logic.
 
@@ -79,16 +75,6 @@ When using the Clock component, you manipulate
 :class:`Symfony\\Component\\Clock\\DatePoint` instances. You can learn more
 about it in :ref:`the dedicated section <clock_date-point>`.
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\Clock\\Clock` class and ``now()`` function
-    were introduced in Symfony 6.3.
-
-.. versionadded:: 6.4
-
-    The ``modifier`` argument of the ``now()`` function was introduced in
-    Symfony 6.4.
-
 Available Clocks Implementations
 --------------------------------
 
@@ -208,10 +194,6 @@ you can set the current time arbitrarily without having to change your service c
 This will help you test every case of your method without the need of actually
 being in a month or another.
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\Clock\\ClockAwareTrait` was introduced in Symfony 6.3.
-
 .. _clock_date-point:
 
 The ``DatePoint`` Class
@@ -247,16 +229,73 @@ The constructor also allows setting a timezone or custom referenced date::
     $referenceDate = new \DateTimeImmutable();
     $relativeDate = new DatePoint('+1month', reference: $referenceDate);
 
+The ``DatePoint`` class also provides a named constructor to create dates from
+timestamps::
+
+    $dateOfFirstCommitToSymfonyProject = DatePoint::createFromTimestamp(1129645656);
+    // equivalent to:
+    // $dateOfFirstCommitToSymfonyProject = (new \DateTimeImmutable())->setTimestamp(1129645656);
+
+    // negative timestamps (for dates before January 1, 1970) and float timestamps
+    // (for high precision sub-second datetimes) are also supported
+    $dateOfFirstMoonLanding = DatePoint::createFromTimestamp(-14182940);
+
+.. versionadded:: 7.1
+
+    The ``createFromTimestamp()`` method was introduced in Symfony 7.1.
+
 .. note::
 
     In addition ``DatePoint`` offers stricter return types and provides consistent
     error handling across versions of PHP, thanks to polyfilling `PHP 8.3's behavior`_
     on the topic.
 
-.. versionadded:: 6.4
+``DatePoint`` also allows to set and get the microsecond part of the date and time::
+
+    $datePoint = new DatePoint();
+    $datePoint->setMicrosecond(345);
+    $microseconds = $datePoint->getMicrosecond();
+
+.. note::
+
+    This feature polyfills PHP 8.4's behavior on the topic, as microseconds manipulation
+    is not available in previous versions of PHP.
+
+.. versionadded:: 7.1
 
-    The :class:`Symfony\\Component\\Clock\\DatePoint` class was introduced
-    in Symfony 6.4.
+    The :method:`Symfony\\Component\\Clock\\DatePoint::setMicrosecond` and
+    :method:`Symfony\\Component\\Clock\\DatePoint::getMicrosecond` methods were
+    introduced in Symfony 7.1.
+
+Storing DatePoints in the Database
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you :doc:`use Doctrine </doctrine>` to work with databases, consider using the
+``date_point`` Doctrine type, which converts to/from ``DatePoint`` objects automatically::
+
+    // src/Entity/Product.php
+    namespace App\Entity;
+
+    use Doctrine\ORM\Mapping as ORM;
+    use Symfony\Component\Clock\DatePoint;
+
+    #[ORM\Entity]
+    class Product
+    {
+        // if you don't define the Doctrine type explicitly, Symfony will autodetect it:
+        #[ORM\Column]
+        private DatePoint $createdAt;
+
+        // if you prefer to define the Doctrine type explicitly:
+        #[ORM\Column(type: 'date_point')]
+        private DatePoint $updatedAt;
+
+        // ...
+    }
+
+.. versionadded:: 7.3
+
+    The ``DatePointType`` was introduced in Symfony 7.3.
 
 .. _clock_writing-tests:
 
@@ -314,10 +353,6 @@ By combining the :class:`Symfony\\Component\\Clock\\ClockAwareTrait` and
 :class:`Symfony\\Component\\Clock\\Test\\ClockSensitiveTrait`, you have full
 control on your time-sensitive code's behavior.
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\Clock\\Test\\ClockSensitiveTrait` was introduced in Symfony 6.3.
-
 Exceptions Management
 ---------------------
 
@@ -338,11 +373,6 @@ These exceptions are available starting from PHP 8.3. However, thanks to the
 `symfony/polyfill-php83`_ dependency required by the Clock component, you can
 use them even if your project doesn't use PHP 8.3 yet.
 
-.. versionadded:: 6.4
-
-    The support for ``DateMalformedStringException`` and
-    ``DateInvalidTimeZoneException`` was introduced in Symfony 6.4.
-
 .. _`PSR-20`: https://www.php-fig.org/psr/psr-20/
 .. _`accepted by the DateTime constructor`: https://www.php.net/manual/en/datetime.formats.php
 .. _`PHP DateTime exceptions`: https://wiki.php.net/rfc/datetime-exceptions
diff --git a/components/config/caching.rst b/components/config/caching.rst
index f30128a5f9d..80e23a4fdfb 100644
--- a/components/config/caching.rst
+++ b/components/config/caching.rst
@@ -55,3 +55,17 @@ the cache file itself. This ``.meta`` file contains the serialized resources,
 whose timestamps are used to determine if the cache is still fresh. When
 not in debug mode, the cache is considered to be "fresh" as soon as it exists,
 and therefore no ``.meta`` file will be generated.
+
+You can explicitly define the absolute path to the meta file::
+
+    use Symfony\Component\Config\ConfigCache;
+    use Symfony\Component\Config\Resource\FileResource;
+
+    $cachePath = __DIR__.'/cache/appUserMatcher.php';
+
+    // the third optional argument indicates the absolute path to the meta file
+    $userMatcherCache = new ConfigCache($cachePath, true, '/my/absolute/path/to/cache.meta');
+
+.. versionadded:: 7.1
+
+    The argument to customize the meta file path was introduced in Symfony 7.1.
diff --git a/components/config/definition.rst b/components/config/definition.rst
index 96f0c177aaa..2b1841bc24a 100644
--- a/components/config/definition.rst
+++ b/components/config/definition.rst
@@ -83,9 +83,19 @@ reflect the real structure of the configuration values::
             ->scalarNode('default_connection')
                 ->defaultValue('mysql')
             ->end()
+            ->stringNode('username')
+                ->defaultValue('root')
+            ->end()
+            ->stringNode('password')
+                ->defaultValue('root')
+            ->end()
         ->end()
     ;
 
+.. versionadded:: 7.2
+
+    The ``stringNode()`` method was introduced in Symfony 7.2.
+
 The root node itself is an array node, and has children, like the boolean
 node ``auto_connect`` and the scalar node ``default_connection``. In general:
 after defining a node, a call to ``end()`` takes you one step up in the
@@ -100,6 +110,7 @@ node definition. Node types are available for:
 * scalar (generic type that includes booleans, strings, integers, floats
   and ``null``)
 * boolean
+* string
 * integer
 * float
 * enum (similar to scalar, but it only allows a finite set of values)
@@ -109,6 +120,10 @@ node definition. Node types are available for:
 and are created with ``node($name, $type)`` or their associated shortcut
 ``xxxxNode($name)`` method.
 
+.. versionadded:: 7.2
+
+    Support for the ``string`` type was introduced in Symfony 7.2.
+
 Numeric Node Constraints
 ~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -171,10 +186,24 @@ The configuration can now be written like this::
         ->end()
     ;
 
-.. versionadded:: 6.3
+You can also use the ``enumFqcn()`` method to pass the FQCN of an enum
+class to the node. This will automatically set the values of the node to
+the cases of the enum::
+
+    $rootNode
+        ->children()
+            ->enumNode('delivery')
+                ->enumFqcn(Delivery::class)
+            ->end()
+        ->end()
+    ;
+
+When using a backed enum, the values provided to the node will be cast
+to one of the enum cases if possible.
 
-    The support of enum values in ``enumNode()`` was introduced
-    in Symfony 6.3.
+.. versionadded:: 7.3
+
+    The ``enumFqcn()`` method was introduced in Symfony 7.3.
 
 Array Nodes
 ~~~~~~~~~~~
@@ -517,6 +546,30 @@ and in XML:
     <!-- entries-per-page: This value is only used for the search results page. -->
     <config entries-per-page="25"/>
 
+You can also provide a URL to a full documentation page::
+
+    $rootNode
+        ->docUrl('Full documentation is available at https://example.com/docs/{version:major}.{version:minor}/reference.html')
+        ->children()
+            ->integerNode('entries_per_page')
+                ->defaultValue(25)
+            ->end()
+        ->end()
+    ;
+
+A few placeholders are available to customize the URL:
+
+* ``{version:major}``: The major version of the package currently installed
+* ``{version:minor}``: The minor version of the package currently installed
+* ``{package}``: The name of the package
+
+The placeholders will be replaced when printing the configuration tree with the
+``config:dump-reference`` command.
+
+.. versionadded:: 7.3
+
+    The ``docUrl()`` method was introduced in Symfony 7.3.
+
 Optional Sections
 -----------------
 
@@ -805,6 +858,7 @@ A validation rule always has an "if" part. You can specify this part in
 the following ways:
 
 - ``ifTrue()``
+- ``ifFalse()``
 - ``ifString()``
 - ``ifNull()``
 - ``ifEmpty()``
@@ -823,6 +877,10 @@ A validation rule also requires a "then" part:
 Usually, "then" is a closure. Its return value will be used as a new value
 for the node, instead of the node's original value.
 
+.. versionadded:: 7.3
+
+    The ``ifFalse()`` method was introduced in Symfony 7.3.
+
 Configuring the Node Path Separator
 -----------------------------------
 
diff --git a/components/console/changing_default_command.rst b/components/console/changing_default_command.rst
index c69995ea395..2195bbd2697 100644
--- a/components/console/changing_default_command.rst
+++ b/components/console/changing_default_command.rst
@@ -9,20 +9,14 @@ name to the ``setDefaultCommand()`` method::
 
     use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
+    use Symfony\Component\Console\Style\SymfonyStyle;
 
-    #[AsCommand(name: 'hello:world')]
+    #[AsCommand(name: 'hello:world', description: 'Outputs "Hello World"')]
     class HelloWorldCommand extends Command
     {
-        protected function configure(): void
+        public function __invoke(SymfonyStyle $io): int
         {
-            $this->setDescription('Outputs "Hello World"');
-        }
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
-        {
-            $output->writeln('Hello World');
+            $io->writeln('Hello World');
 
             return Command::SUCCESS;
         }
diff --git a/components/console/events.rst b/components/console/events.rst
index ab497068979..699ba444747 100644
--- a/components/console/events.rst
+++ b/components/console/events.rst
@@ -156,11 +156,6 @@ Listeners receive a
     a signal. You can learn more about signals in the
     :ref:`the dedicated section <console-events_signal>`.
 
-    .. versionadded:: 6.4
-
-        Dispatching the ``ConsoleEvents::TERMINATE`` event on exit
-        signal was introduced in Symfony 6.4.
-
 .. _console-events_signal:
 
 The ``ConsoleEvents::SIGNAL`` Event
@@ -207,11 +202,6 @@ method::
         $event->abortExit();
     });
 
-.. versionadded:: 6.3
-
-    The ``setExitCode()``, ``getExitCode()`` and ``abortExit()`` methods were introduced
-    in Symfony 6.3.
-
 .. tip::
 
     All the available signals (``SIGINT``, ``SIGQUIT``, etc.) are defined as
@@ -219,36 +209,32 @@ method::
     for these constants to be available.
 
 If you use the Console component inside a Symfony application, commands can
-handle signals themselves. To do so, implement the
-:class:`Symfony\\Component\\Console\\Command\\SignalableCommandInterface` and subscribe to one or more signals::
+handle signals themselves by subscribing to the :class:`Symfony\\Component\\Console\\Event\\ConsoleSignalEvent` event::
 
-    // src/Command/SomeCommand.php
+    // src/Command/MyCommand.php
     namespace App\Command;
 
-    use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Command\SignalableCommandInterface;
+    use Symfony\Component\Console\Attribute\AsCommand;
+    use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
 
-    class SomeCommand extends Command implements SignalableCommandInterface
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
         // ...
 
-        public function getSubscribedSignals(): array
-        {
-            // return here any of the constants defined by PCNTL extension
-            return [\SIGINT, \SIGTERM];
-        }
-
-        public function handleSignal(int $signal): int|false
+        #[AsEventListener(ConsoleSignalEvent::class)]
+        public function handleSignal(ConsoleSignalEvent $event): void
         {
-            if (\SIGINT === $signal) {
+            // set here any of the constants defined by PCNTL extension
+            if (in_array($event->getHandlingSignal(), [\SIGINT, \SIGTERM], true)) {
                 // ...
             }
 
             // ...
 
-            // return an integer to set the exit code, or
+            // set an integer exit code, or
             // false to continue normal execution
-            return 0;
+            $event->setExitCode(0);
         }
     }
 
@@ -263,21 +249,6 @@ handle all signals e.g. to do some tasks before terminating the command.
     :method:`Symfony\\Component\\Console\\SignalRegistry\\SignalMap::getSignalName`
     method.
 
-    .. versionadded:: 6.4
-
-        The :class:`Symfony\\Component\\Console\\SignalRegistry\\SignalMap` class was
-        introduced in Symfony 6.4.
-
-.. deprecated:: 6.3
-
-    In Symfony versions previous to 6.3, all signals (except ``SIGUSR1`` and
-    ``SIGUSR2``) would terminate the script by calling ``exit(0)``. Starting
-    from Symfony 6.3, no more signal is automatically calling ``exit(0)``.
-
-.. deprecated:: 6.3
-
-    Not returning a value in ``handleSignal()`` is deprecated since Symfony 6.3.
-
 .. _`reserved exit codes`: https://www.tldp.org/LDP/abs/html/exitcodes.html
 .. _`Signals`: https://en.wikipedia.org/wiki/Signal_(IPC)
 .. _`constants of the PCNTL PHP extension`: https://www.php.net/manual/en/pcntl.constants.php
diff --git a/components/console/helpers/cursor.rst b/components/console/helpers/cursor.rst
index c5cab6c6d0b..63045f178ad 100644
--- a/components/console/helpers/cursor.rst
+++ b/components/console/helpers/cursor.rst
@@ -13,16 +13,16 @@ of the output:
     // src/Command/MyCommand.php
     namespace App\Command;
 
-    use Symfony\Component\Console\Command\Command;
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Cursor;
-    use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
 
-    class MyCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
         // ...
 
-        public function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output): int
         {
             // ...
 
diff --git a/components/console/helpers/debug_formatter.rst b/components/console/helpers/debug_formatter.rst
index 10d3c67a79a..8fa59c319c9 100644
--- a/components/console/helpers/debug_formatter.rst
+++ b/components/console/helpers/debug_formatter.rst
@@ -10,15 +10,14 @@ this:
 .. image:: /_images/components/console/debug_formatter.png
     :alt: Console output, with the first line showing "RUN Running figlet", followed by lines showing the output of the command prefixed with "OUT" and "RES Finished the command" as last line in the output.
 
-Using the debug_formatter
+Using the Debug Formatter
 -------------------------
 
-The formatter is included in the default helper set and you can get it by
-calling :method:`Symfony\\Component\\Console\\Command\\Command::getHelper`::
+The debug formatter helper can be instantiated directly as shown::
 
-    $debugFormatter = $this->getHelper('debug_formatter');
+    $debugFormatter = new DebugFormatterHelper();
 
-The formatter accepts strings and returns a formatted string, which you then
+It accepts strings and returns a formatted string, which you then
 output to the console (or even log the information or do anything else).
 
 All methods of this helper have an identifier as the first argument. This is a
diff --git a/components/console/helpers/formatterhelper.rst b/components/console/helpers/formatterhelper.rst
index 1ff6bff189b..cf9bacdeb9c 100644
--- a/components/console/helpers/formatterhelper.rst
+++ b/components/console/helpers/formatterhelper.rst
@@ -1,15 +1,11 @@
 Formatter Helper
 ================
 
-The Formatter helper provides functions to format the output with colors.
-You can do more advanced things with this helper than you can in
-:doc:`/console/coloring`.
+The :class:`Symfony\\Component\\Console\\Helper\\FormatterHelper` helper provides
+functions to format the output with colors. You can do more advanced things with
+this helper than you can with the :doc:`basic colors and styles </console/coloring>`::
 
-The :class:`Symfony\\Component\\Console\\Helper\\FormatterHelper` is included
-in the default helper set and you can get it by calling
-:method:`Symfony\\Component\\Console\\Command\\Command::getHelper`::
-
-    $formatter = $this->getHelper('formatter');
+    $formatter = new FormatterHelper();
 
 The methods return a string, which you'll usually render to the console by
 passing it to the
@@ -129,14 +125,16 @@ Sometimes you want to format seconds to time. This is possible with the
 The first argument is the seconds to format and the second argument is the
 precision (default ``1``) of the result::
 
-    Helper::formatTime(42);        // 42 secs
-    Helper::formatTime(125);       // 2 mins
-    Helper::formatTime(125, 2);    // 2 mins, 5 secs
-    Helper::formatTime(172799, 4); // 1 day, 23 hrs, 59 mins, 59 secs
+    Helper::formatTime(0.001);         // 1 ms
+    Helper::formatTime(42);            // 42 s
+    Helper::formatTime(125);           // 2 min
+    Helper::formatTime(125, 2);        // 2 min, 5 s
+    Helper::formatTime(172799, 4);     // 1 d, 23 h, 59 min, 59 s
+    Helper::formatTime(172799.056, 5); // 1 d, 23 h, 59 min, 59 s, 56 ms
 
-.. versionadded:: 6.4
+.. versionadded:: 7.3
 
-    The support for exact times was introduced in Symfony 6.4.
+    Support for formatting up to milliseconds was introduced in Symfony 7.3.
 
 Formatting Memory
 -----------------
diff --git a/components/console/helpers/map.rst.inc b/components/console/helpers/map.rst.inc
index 41f0667c40d..73d5d4da7a0 100644
--- a/components/console/helpers/map.rst.inc
+++ b/components/console/helpers/map.rst.inc
@@ -4,5 +4,6 @@
 * :doc:`/components/console/helpers/progressindicator`
 * :doc:`/components/console/helpers/questionhelper`
 * :doc:`/components/console/helpers/table`
+* :doc:`/components/console/helpers/tree`
 * :doc:`/components/console/helpers/debug_formatter`
 * :doc:`/components/console/helpers/cursor`
diff --git a/components/console/helpers/processhelper.rst b/components/console/helpers/processhelper.rst
index b46d9f2e95f..df9a8efe45b 100644
--- a/components/console/helpers/processhelper.rst
+++ b/components/console/helpers/processhelper.rst
@@ -11,7 +11,7 @@ a very verbose verbosity (e.g. ``-vv``)::
 
     use Symfony\Component\Process\Process;
 
-    $helper = $this->getHelper('process');
+    $helper = new ProcessHelper();
     $process = new Process(['figlet', 'Symfony']);
 
     $helper->run($output, $process);
diff --git a/components/console/helpers/progressbar.rst b/components/console/helpers/progressbar.rst
index 445fb1dda88..19e2d0daef5 100644
--- a/components/console/helpers/progressbar.rst
+++ b/components/console/helpers/progressbar.rst
@@ -69,10 +69,6 @@ that starting point::
     // displays the progress bar starting at 25 completed units
     $progressBar->start(null, 25);
 
-.. versionadded:: 6.2
-
-    The option to start a progress bar at a certain point was introduced in Symfony 6.2.
-
 .. tip::
 
     If your platform doesn't support ANSI codes, updates to the progress
@@ -375,10 +371,6 @@ with the ``setPlaceholderFormatter`` method::
         return $progressBar->getMaxSteps() - $progressBar->getProgress();
     });
 
-.. versionadded:: 6.3
-
-    The ``setPlaceholderFormatter()`` method was introduced in Symfony 6.3.
-
 Custom Messages
 ~~~~~~~~~~~~~~~
 
diff --git a/components/console/helpers/progressindicator.rst b/components/console/helpers/progressindicator.rst
index d64ec6367b7..0defe7c83fd 100644
--- a/components/console/helpers/progressindicator.rst
+++ b/components/console/helpers/progressindicator.rst
@@ -44,18 +44,21 @@ level of verbosity of the ``OutputInterface`` instance:
      | Processing...
      / Processing...
      - Processing...
+     ✔ Finished
 
     # OutputInterface::VERBOSITY_VERBOSE (-v)
      \ Processing... (1 sec)
      | Processing... (1 sec)
      / Processing... (1 sec)
      - Processing... (1 sec)
+     ✔ Finished (1 sec)
 
     # OutputInterface::VERBOSITY_VERY_VERBOSE (-vv) and OutputInterface::VERBOSITY_DEBUG (-vvv)
      \ Processing... (1 sec, 6.0 MiB)
      | Processing... (1 sec, 6.0 MiB)
      / Processing... (1 sec, 6.0 MiB)
      - Processing... (1 sec, 6.0 MiB)
+     ✔ Finished (1 sec, 6.0 MiB)
 
 .. tip::
 
@@ -94,6 +97,34 @@ The progress indicator will now look like this:
      ⠛ Processing...
      ⠹ Processing...
      ⢸ Processing...
+     ✔ Finished
+
+Once the progress finishes, it displays a special finished indicator (which defaults
+to ✔). You can replace it with your own::
+
+    $progressIndicator = new ProgressIndicator($output, finishedIndicatorValue: '🎉');
+    
+    try {
+        /* do something */
+        $progressIndicator->finish('Finished');
+    } catch (\Exception) {
+        $progressIndicator->finish('Failed', '🚨');
+    }
+
+The progress indicator will now look like this:
+
+.. code-block:: text
+
+     \ Processing...
+     | Processing...
+     / Processing...
+     - Processing...
+     🎉 Finished
+
+.. versionadded:: 7.2
+
+    The ``finishedIndicator`` parameter for the constructor was introduced in Symfony 7.2.
+    The ``finishedIndicator`` parameter for method ``finish()`` was introduced in Symfony 7.2.
 
 Customize Placeholders
 ~~~~~~~~~~~~~~~~~~~~~~
diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst
index 3dc97d5c0d3..6d22a2de2af 100644
--- a/components/console/helpers/questionhelper.rst
+++ b/components/console/helpers/questionhelper.rst
@@ -2,11 +2,9 @@ Question Helper
 ===============
 
 The :class:`Symfony\\Component\\Console\\Helper\\QuestionHelper` provides
-functions to ask the user for more information. It is included in the default
-helper set and you can get it by calling
-:method:`Symfony\\Component\\Console\\Command\\Command::getHelper`::
+functions to ask the user for more information::
 
-    $helper = $this->getHelper('question');
+    $helper = new QuestionHelper();
 
 The Question Helper has a single method
 :method:`Symfony\\Component\\Console\\Helper\\QuestionHelper::ask` that needs an
@@ -27,18 +25,18 @@ Suppose you want to confirm an action before actually executing it. Add
 the following to your command::
 
     // ...
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
     use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
     use Symfony\Component\Console\Question\ConfirmationQuestion;
 
-    class YourCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        // ...
-
-        public function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(InputInterface $input, OutputInterface $output): int
         {
-            $helper = $this->getHelper('question');
+            $helper = new QuestionHelper();
             $question = new ConfirmationQuestion('Continue with this action?', false);
 
             if (!$helper->ask($input, $output, $question)) {
@@ -91,7 +89,7 @@ if you want to know a bundle name, you can add this to your command::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
         $question = new Question('Please enter the name of the bundle', 'AcmeDemoBundle');
@@ -121,10 +119,10 @@ but ``red`` could be set instead (could be more explicit)::
     use Symfony\Component\Console\Question\ChoiceQuestion;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
         $question = new ChoiceQuestion(
             'Please select your favorite color (defaults to red)',
             // choices can also be PHP objects that implement __toString() method
@@ -184,10 +182,10 @@ this use :method:`Symfony\\Component\\Console\\Question\\ChoiceQuestion::setMult
     use Symfony\Component\Console\Question\ChoiceQuestion;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
         $question = new ChoiceQuestion(
             'Please select your favorite colors (defaults to red and blue)',
             ['red', 'blue', 'yellow'],
@@ -218,10 +216,10 @@ will be autocompleted as the user types::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $bundles = ['AcmeDemoBundle', 'AcmeBlogBundle', 'AcmeStoreBundle'];
         $question = new Question('Please enter the name of a bundle', 'FooBundle');
@@ -241,9 +239,9 @@ provide a callback function to dynamically generate suggestions::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         // This function is called whenever the input changes and new
         // suggestions are needed.
@@ -282,10 +280,10 @@ You can also specify if you want to not trim the answer by setting it directly w
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $question = new Question('What is the name of the child?');
         $question->setTrimmable(false);
@@ -308,10 +306,10 @@ the response to a question should allow multiline answers by passing ``true`` to
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $question = new Question('How do you solve world peace?');
         $question->setMultiline(true);
@@ -335,10 +333,10 @@ convenient for passwords::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $question = new Question('What is the database password?');
         $question->setHidden(true);
@@ -372,10 +370,10 @@ convenient for passwords::
         use Symfony\Component\Console\Question\ChoiceQuestion;
 
         // ...
-        public function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(InputInterface $input, OutputInterface $output): int
         {
             // ...
-            $helper = $this->getHelper('question');
+            $helper = new QuestionHelper();
             QuestionHelper::disableStty();
 
             // ...
@@ -396,10 +394,10 @@ method::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $question = new Question('Please enter the name of the bundle', 'AcmeDemoBundle');
         $question->setNormalizer(function (string $value): string {
@@ -434,10 +432,10 @@ method::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $question = new Question('Please enter the name of the bundle', 'AcmeDemoBundle');
         $question->setValidator(function (string $answer): string {
@@ -480,10 +478,10 @@ invalid answer and will only be able to proceed if their input is valid.
         use Symfony\Component\Validator\Validation;
 
         $question = new Question('Please enter the name of the bundle', 'AcmeDemoBundle');
-        $validation = Validation::createCallable(new Regex([
-            'pattern' => '/^[a-zA-Z]+Bundle$/',
-            'message' => 'The name of the bundle should be suffixed with \'Bundle\'',
-        ]));
+        $validation = Validation::createCallable(new Regex(
+            pattern: '/^[a-zA-Z]+Bundle$/',
+            message: 'The name of the bundle should be suffixed with \'Bundle\'',
+        ));
         $question->setValidator($validation);
 
 Validating a Hidden Response
@@ -494,10 +492,10 @@ You can also use a validator with a hidden question::
     use Symfony\Component\Console\Question\Question;
 
     // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(InputInterface $input, OutputInterface $output): int
     {
         // ...
-        $helper = $this->getHelper('question');
+        $helper = new QuestionHelper();
 
         $question = new Question('Please enter your password');
         $question->setNormalizer(function (?string $value): string {
diff --git a/components/console/helpers/table.rst b/components/console/helpers/table.rst
index 6d48d92a98a..e36b1570b70 100644
--- a/components/console/helpers/table.rst
+++ b/components/console/helpers/table.rst
@@ -10,15 +10,16 @@ features, use the ``Table`` console helper explained in this article.
 To display a table, use :class:`Symfony\\Component\\Console\\Helper\\Table`,
 set the headers, set the rows and then render the table::
 
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
     use Symfony\Component\Console\Helper\Table;
-    use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
     // ...
 
-    class SomeCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        public function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output): int
         {
             $table = new Table($output);
             $table
@@ -192,10 +193,6 @@ This outputs:
     | Author: Charles Dickens      |
     +------------------------------+
 
-.. versionadded:: 6.1
-
-    Support for vertical rendering was introduced in Symfony 6.1.
-
 Customizing the Table Style
 ---------------------------
 
@@ -277,6 +274,26 @@ This outputs:
     ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie  ║
     ╚═══════════════╧══════════════════════════╧══════════════════╝
 
+**Markdown**::
+
+    $table->setStyle('markdown');
+    $table->render();
+
+This outputs:
+
+.. code-block:: terminal
+
+    | ISBN          | Title                    | Author           |
+    |---------------|--------------------------|------------------|
+    | 99921-58-10-7 | Divine Comedy            | Dante Alighieri  |
+    | 9971-5-0210-0 | A Tale of Two Cities     | Charles Dickens  |
+    | 960-425-059-0 | The Lord of the Rings    | J. R. R. Tolkien |
+    | 80-902734-1-6 | And Then There Were None | Agatha Christie  |
+
+.. versionadded:: 7.3
+
+    The ``markdown`` style was introduced in Symfony 7.3.
+
 Making a Custom Table Style
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -456,9 +473,10 @@ The only requirement to append rows is that the table must be rendered inside a
     use Symfony\Component\Console\Helper\Table;
     // ...
 
-    class SomeCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        public function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output): int
         {
             $section = $output->section();
             $table = new Table($section);
diff --git a/components/console/helpers/tree.rst b/components/console/helpers/tree.rst
new file mode 100644
index 00000000000..5e08e684e51
--- /dev/null
+++ b/components/console/helpers/tree.rst
@@ -0,0 +1,336 @@
+Tree Helper
+===========
+
+The Tree Helper allows you to build and display tree structures in the console.
+It's commonly used to render directory hierarchies, but you can also use it to render
+any tree-like content, such us organizational charts, product category trees, taxonomies, etc.
+
+.. versionadded:: 7.3
+
+    The ``TreeHelper`` class was introduced in Symfony 7.3.
+
+Rendering a Tree
+----------------
+
+The :method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` method
+creates a tree structure from an array and returns a :class:`Symfony\\Component\\Console\\Helper\\Tree`
+object that can be rendered in the console.
+
+Rendering a Tree from an Array
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can build a tree from an array by passing the array to the
+:method:`Symfony\\Component\\Console\\Helper\\TreeHelper::createTree` method
+inside your console command::
+
+    namespace App\Command;
+
+    use Symfony\Component\Console\Attribute\AsCommand;
+    use Symfony\Component\Console\Helper\TreeHelper;
+    use Symfony\Component\Console\Helper\TreeNode;
+    use Symfony\Component\Console\Style\SymfonyStyle;
+
+    #[AsCommand(name: 'app:my-command', description: '...')]
+    class MyCommand
+    {
+        // ...
+
+        public function __invoke(SymfonyStyle $io): int
+        {
+            $node = TreeNode::fromValues([
+                'config/',
+                'public/',
+                'src/',
+                'templates/',
+                'tests/',
+            ]);
+
+            $tree = TreeHelper::createTree($io, $node);
+            $tree->render();
+
+            // ...
+        }
+    }
+
+This exampe would output the following:
+
+.. code-block:: terminal
+
+    ├── config/
+    ├── public/
+    ├── src/
+    ├── templates/
+    └── tests/
+
+The given contents can be defined in a multi-dimensional array::
+
+    $tree = TreeHelper::createTree($io, null, [
+        'src' =>  [
+            'Command',
+            'Controller' => [
+                'DefaultController.php',
+            ],
+            'Kernel.php',
+        ],
+        'templates' => [
+            'base.html.twig',
+        ],
+    ]);
+
+    $tree->render();
+
+The above code will output the following tree:
+
+.. code-block:: terminal
+
+    ├── src
+    │   ├── Command
+    │   ├── Controller
+    │   │   └── DefaultController.php
+    │   └── Kernel.php
+    └── templates
+        └── base.html.twig
+
+Building a Tree Programmatically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you don't know the tree elements beforehand, you can build the tree programmatically
+by creating a new instance of the :class:`Symfony\\Component\\Console\\Helper\\Tree`
+class and adding nodes to it::
+
+    use Symfony\Component\Console\Helper\TreeHelper;
+    use Symfony\Component\Console\Helper\TreeNode;
+
+    $root = new TreeNode('my-project/');
+    // you can pass a string directly or create a TreeNode object
+    $root->addChild('src/');
+    $root->addChild(new TreeNode('templates/'));
+
+    // create nested structures by adding child nodes to other nodes
+    $testsNode = new TreeNode('tests/');
+    $functionalTestsNode = new TreeNode('Functional/');
+    $testsNode->addChild($functionalTestsNode);
+    $root->addChild($testsNode);
+
+    $tree = TreeHelper::createTree($io, $root);
+    $tree->render();
+
+This example outputs:
+
+.. code-block:: terminal
+
+    my-project/
+    ├── src/
+    ├── templates/
+    └── tests/
+        └── Functional/
+
+If you prefer, you can build the array of elements programmatically and then
+create and render the tree like this::
+
+    $tree = TreeHelper::createTree($io, null, $array);
+    $tree->render();
+
+You can also build part of the tree from an array and then add other nodes::
+
+    $node = TreeNode::fromValues($array);
+    $node->addChild('templates');
+    // ...
+    $tree = TreeHelper::createTree($io, $node);
+    $tree->render();
+
+Customizing the Tree Style
+--------------------------
+
+Built-in Tree Styles
+~~~~~~~~~~~~~~~~~~~~
+
+The tree helper provides a few built-in styles that you can use to customize the
+output of the tree.
+
+**Default**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::default());
+
+This outputs:
+
+.. code-block:: terminal
+
+    ├── config
+    │   ├── packages
+    │   └── routes
+    │      ├── framework.yaml
+    │      └── web_profiler.yaml
+    ├── src
+    │   ├── Command
+    │   ├── Controller
+    │   │   └── DefaultController.php
+    │   └── Kernel.php
+    └── templates
+       └── base.html.twig
+
+**Box**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::box());
+
+This outputs:
+
+.. code-block:: terminal
+
+    ┃╸ config
+    ┃  ┃╸ packages
+    ┃  ┗╸ routes
+    ┃     ┃╸ framework.yaml
+    ┃     ┗╸ web_profiler.yaml
+    ┃╸ src
+    ┃  ┃╸ Command
+    ┃  ┃╸ Controller
+    ┃  ┃  ┗╸ DefaultController.php
+    ┃  ┗╸ Kernel.php
+    ┗╸ templates
+       ┗╸ base.html.twig
+
+**Double box**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::doubleBox());
+
+This outputs:
+
+.. code-block:: terminal
+
+    ╠═ config
+    ║  ╠═ packages
+    ║  ╚═ routes
+    ║    ╠═ framework.yaml
+    ║    ╚═ web_profiler.yaml
+    ╠═ src
+    ║  ╠═ Command
+    ║  ╠═ Controller
+    ║  ║  ╚═ DefaultController.php
+    ║  ╚═ Kernel.php
+    ╚═ templates
+      ╚═ base.html.twig
+
+**Compact**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::compact());
+
+This outputs:
+
+.. code-block:: terminal
+
+    ├ config
+    │ ├ packages
+    │ └ routes
+    │   ├ framework.yaml
+    │   └ web_profiler.yaml
+    ├ src
+    │ ├ Command
+    │ ├ Controller
+    │ │ └ DefaultController.php
+    │ └ Kernel.php
+    └ templates
+      └ base.html.twig
+
+**Light**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::light());
+
+This outputs:
+
+.. code-block:: terminal
+
+    |-- config
+    |   |-- packages
+    |   `-- routes
+    |       |-- framework.yaml
+    |       `-- web_profiler.yaml
+    |-- src
+    |   |-- Command
+    |   |-- Controller
+    |   |   `-- DefaultController.php
+    |   `-- Kernel.php
+    `-- templates
+        `-- base.html.twig
+
+**Minimal**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::minimal());
+
+This outputs:
+
+.. code-block:: terminal
+
+    . config
+    . . packages
+    . . routes
+    .   . framework.yaml
+    .   . web_profiler.yaml
+    . src
+    . . Command
+    . . Controller
+    . . . DefaultController.php
+    . . Kernel.php
+    . templates
+      . base.html.twig
+
+**Rounded**::
+
+    TreeHelper::createTree($io, $node, [], TreeStyle::rounded());
+
+This outputs:
+
+.. code-block:: terminal
+
+    ├─ config
+    │  ├─ packages
+    │  ╰─ routes
+    │     ├─ framework.yaml
+    │     ╰─ web_profiler.yaml
+    ├─ src
+    │  ├─ Command
+    │  ├─ Controller
+    │  │  ╰─ DefaultController.php
+    │  ╰─ Kernel.php
+    ╰─ templates
+       ╰─ base.html.twig
+
+Making a Custom Tree Style
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can create your own tree style by passing the characters to the constructor
+of the :class:`Symfony\\Component\\Console\\Helper\\TreeStyle` class::
+
+    use Symfony\Component\Console\Helper\TreeHelper;
+    use Symfony\Component\Console\Helper\TreeStyle;
+
+    $customStyle = new TreeStyle('🟣 ', '🟠 ', '🔵 ', '🟢 ', '🔴 ', '🟡 ');
+
+    // Pass the custom style to the createTree method
+
+    $tree = TreeHelper::createTree($io, null, [
+        'src' =>  [
+            'Command',
+            'Controller' => [
+                'DefaultController.php',
+            ],
+            'Kernel.php',
+        ],
+        'templates' => [
+            'base.html.twig',
+        ],
+    ], $customStyle);
+
+    $tree->render();
+
+The above code will output the following tree:
+
+.. code-block:: terminal
+
+    🔵 🟣 🟡 src
+    🔵 🟢 🟣 🟡 Command
+    🔵 🟢 🟣 🟡 Controller
+    🔵 🟢 🟢 🟠 🟡 DefaultController.php
+    🔵 🟢 🟠 🟡 Kernel.php
+    🔵 🟠 🟡 templates
+    🔵 🔴 🟠 🟡 base.html.twig
diff --git a/components/console/logger.rst b/components/console/logger.rst
index 4af0b9a3f2f..cc182821a0a 100644
--- a/components/console/logger.rst
+++ b/components/console/logger.rst
@@ -34,7 +34,6 @@ You can rely on the logger to use this dependency inside a command::
     use Acme\MyDependency;
     use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Logger\ConsoleLogger;
     use Symfony\Component\Console\Output\OutputInterface;
 
@@ -42,16 +41,16 @@ You can rely on the logger to use this dependency inside a command::
         name: 'my:command',
         description: 'Use an external dependency requiring a PSR-3 logger'
     )]
-    class MyCommand extends Command
+    class MyCommand
     {
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output): int
         {
             $logger = new ConsoleLogger($output);
 
             $myDependency = new MyDependency($logger);
             $myDependency->doStuff();
 
-            // ...
+            return Command::SUCCESS;
         }
     }
 
diff --git a/components/console/single_command_tool.rst b/components/console/single_command_tool.rst
index 97cb09bf030..9c6b06537e2 100644
--- a/components/console/single_command_tool.rst
+++ b/components/console/single_command_tool.rst
@@ -9,19 +9,18 @@ it is possible to remove this need by declaring a single command application::
     <?php
     require __DIR__.'/vendor/autoload.php';
 
-    use Symfony\Component\Console\Input\InputArgument;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Input\InputOption;
+    use Symfony\Component\Console\Attribute\Argument;
+    use Symfony\Component\Console\Attribute\Option;
     use Symfony\Component\Console\Output\OutputInterface;
     use Symfony\Component\Console\SingleCommandApplication;
 
     (new SingleCommandApplication())
         ->setName('My Super Command') // Optional
         ->setVersion('1.0.0') // Optional
-        ->addArgument('foo', InputArgument::OPTIONAL, 'The directory')
-        ->addOption('bar', null, InputOption::VALUE_REQUIRED)
-        ->setCode(function (InputInterface $input, OutputInterface $output): int {
+        ->setCode(function (OutputInterface $output, #[Argument] string $foo = 'The directory', #[Option] string $bar = ''): int {
             // output arguments and options
+
+            return 0;
         })
         ->run();
 
diff --git a/components/console/usage.rst b/components/console/usage.rst
index d7725e8926e..591994948b8 100644
--- a/components/console/usage.rst
+++ b/components/console/usage.rst
@@ -65,9 +65,17 @@ You can suppress output with:
 
 .. code-block:: terminal
 
+    # suppresses all output, including errors
+    $ php application.php list --silent
+
+    # suppresses all output except errors
     $ php application.php list --quiet
     $ php application.php list -q
 
+.. versionadded:: 7.2
+
+    The ``--silent`` option was introduced in Symfony 7.2.
+
 You can get more verbose messages (if this is supported for a command)
 with:
 
diff --git a/components/css_selector.rst b/components/css_selector.rst
index 94561cec9bd..1331a11e616 100644
--- a/components/css_selector.rst
+++ b/components/css_selector.rst
@@ -92,11 +92,11 @@ Pseudo-classes are partially supported:
 * Not supported: ``*:first-of-type``, ``*:last-of-type``, ``*:nth-of-type`` and
   ``*:nth-last-of-type`` (all these work with an element name (e.g.
   ``li:first-of-type``) but not with the ``*`` selector).
-* Supported: ``*:only-of-type``, ``*:scope``.
+* Supported: ``*:only-of-type``, ``*:scope``, ``*:is`` and ``*:where``.
 
-.. versionadded:: 6.3
+.. versionadded:: 7.1
 
-    The support for ``*:scope`` was introduced in Symfony 6.3.
+    The support for ``*:is`` and ``*:where`` was introduced in Symfony 7.1.
 
 Learn more
 ----------
diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst
index 7db22a68d5f..c79281b5c27 100644
--- a/components/dependency_injection/compilation.rst
+++ b/components/dependency_injection/compilation.rst
@@ -278,10 +278,6 @@ The parameter being deprecated must be set before being declared as deprecated.
 Otherwise a :class:`Symfony\\Component\\DependencyInjection\\Exception\\ParameterNotFoundException`
 exception will be thrown.
 
-.. versionadded:: 6.3
-
-    The ``ContainerBuilder::deprecateParameter()`` method was introduced in Symfony 6.3.
-
 .. note::
 
     Just registering an extension with the container is not enough to get
diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst
index 00e5d8795ea..630d301302a 100644
--- a/components/dom_crawler.rst
+++ b/components/dom_crawler.rst
@@ -229,11 +229,6 @@ Access the value of the first node of the current selection::
     // but you can get the unchanged text by passing FALSE as argument
     $text = $crawler->filterXPath('//body/p')->innerText(false);
 
-.. versionadded:: 6.3
-
-    The removal of whitespace characters by default in ``innerText()`` was
-    introduced in Symfony 6.3.
-
 Access the attribute value of the first node of the current selection::
 
     $class = $crawler->filterXPath('//body/p')->attr('class');
@@ -245,11 +240,6 @@ Access the attribute value of the first node of the current selection::
 
         $class = $crawler->filterXPath('//body/p')->attr('class', 'my-default-class');
 
-    .. versionadded:: 6.4
-
-        The possibility to specify a default value to the ``attr()`` method
-        was introduced in Symfony 6.4.
-
 Extract attribute and/or node values from the list of nodes::
 
     $attributes = $crawler
@@ -672,10 +662,6 @@ parser, set its ``useHtml5Parser`` constructor argument to ``true``::
 By doing so, the crawler will use the HTML5 parser provided by the `masterminds/html5`_
 library to parse the documents.
 
-.. versionadded:: 6.3
-
-    The ``useHtml5Parser`` argument was introduced in Symfony 6.3.
-
 Learn more
 ----------
 
diff --git a/components/expression_language.rst b/components/expression_language.rst
index 7133932da28..b0dd10b0f42 100644
--- a/components/expression_language.rst
+++ b/components/expression_language.rst
@@ -106,6 +106,33 @@ if the expression is not valid::
 
     $expressionLanguage->lint('1 + 2', []); // doesn't throw anything
 
+    $expressionLanguage->lint('1 + a', []);
+    // throws a SyntaxError exception:
+    // "Variable "a" is not valid around position 5 for expression `1 + a`."
+
+The behavior of these methods can be configured with some flags defined in the
+:class:`Symfony\\Component\\ExpressionLanguage\\Parser` class:
+
+* ``IGNORE_UNKNOWN_VARIABLES``: don't throw an exception if a variable is not
+  defined in the expression;
+* ``IGNORE_UNKNOWN_FUNCTIONS``: don't throw an exception if a function is not
+  defined in the expression.
+
+This is how you can use these flags::
+
+    use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
+    use Symfony\Component\ExpressionLanguage\Parser;
+
+    $expressionLanguage = new ExpressionLanguage();
+
+    // does not throw a SyntaxError because the unknown variables and functions are ignored
+    $expressionLanguage->lint('unknown_var + unknown_function()', [], Parser::IGNORE_UNKNOWN_VARIABLES | Parser::IGNORE_UNKNOWN_FUNCTIONS);
+
+.. versionadded:: 7.1
+
+    The support for flags in the ``parse()`` and ``lint()`` methods
+    was introduced in Symfony 7.1.
+
 Passing in Variables
 --------------------
 
diff --git a/components/filesystem.rst b/components/filesystem.rst
index de1075f0b36..4eae6aaad27 100644
--- a/components/filesystem.rst
+++ b/components/filesystem.rst
@@ -313,6 +313,22 @@ contents at the end of some file::
 If either the file or its containing directory doesn't exist, this method
 creates them before appending the contents.
 
+``readFile``
+~~~~~~~~~~~~
+
+.. versionadded:: 7.1
+
+    The ``readFile()`` method was introduced in Symfony 7.1.
+
+:method:`Symfony\\Component\\Filesystem\\Filesystem::readFile` returns all the
+contents of a file as a string. Unlike the :phpfunction:`file_get_contents` function
+from PHP, it throws an exception when the given file path is not readable and
+when passing the path to a directory instead of a file::
+
+    $contents = $filesystem->readFile('/some/path/to/file.txt');
+
+The ``$contents`` variable now stores all the contents of the ``file.txt`` file.
+
 Path Manipulation Utilities
 ---------------------------
 
diff --git a/components/finder.rst b/components/finder.rst
index 7cc580333e7..cecc597ac64 100644
--- a/components/finder.rst
+++ b/components/finder.rst
@@ -361,10 +361,6 @@ using a closure, return ``false`` for the directories which you want to prune.
 Pruning directories early can improve performance significantly depending on the
 file/directory hierarchy complexity and the number of excluded directories.
 
-.. versionadded:: 6.4
-
-    The feature to prune directories was introduced in Symfony 6.4.
-
 Sorting Results
 ---------------
 
@@ -376,11 +372,6 @@ Sort the results by name, extension, size or type (directories first, then files
     $finder->sortBySize();
     $finder->sortByType();
 
-.. versionadded:: 6.2
-
-    The ``sortByCaseInsensitiveName()``, ``sortByExtension()`` and ``sortBySize()``
-    methods were introduced in Symfony 6.2.
-
 .. tip::
 
     By default, the ``sortByName()`` method uses the :phpfunction:`strcmp` PHP
diff --git a/components/form.rst b/components/form.rst
index e4b1c9a67e9..44f407e4c8e 100644
--- a/components/form.rst
+++ b/components/form.rst
@@ -123,8 +123,7 @@ The following snippet adds CSRF protection to the form factory::
     use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
 
     // creates a RequestStack object using the current request
-    $requestStack = new RequestStack();
-    $requestStack->push($request);
+    $requestStack = new RequestStack([$request]);
 
     $csrfGenerator = new UriSafeTokenGenerator();
     $csrfStorage = new SessionTokenStorage($requestStack);
@@ -135,6 +134,11 @@ The following snippet adds CSRF protection to the form factory::
         ->addExtension(new CsrfExtension($csrfManager))
         ->getFormFactory();
 
+.. versionadded:: 7.2
+
+    Support for passing requests to the constructor of the ``RequestStack``
+    class was introduced in Symfony 7.2.
+
 Internally, this extension will automatically add a hidden field to every
 form (called ``_token`` by default) whose value is automatically generated by
 the CSRF generator and validated when binding the form.
@@ -749,10 +753,11 @@ method to access the list of errors. It returns a
     // "firstName" field
     $errors = $form['firstName']->getErrors();
 
-    // a FormErrorIterator instance in a flattened structure
+    // a FormErrorIterator instance including child forms in a flattened structure
+    // use getOrigin() to determine the form causing the error
     $errors = $form->getErrors(true);
 
-    // a FormErrorIterator instance representing the form tree structure
+    // a FormErrorIterator instance including child forms without flattening the output structure
     $errors = $form->getErrors(true, false);
 
 Clearing Form Errors
diff --git a/components/http_foundation.rst b/components/http_foundation.rst
index 14843bab346..1cb87aafb24 100644
--- a/components/http_foundation.rst
+++ b/components/http_foundation.rst
@@ -145,20 +145,12 @@ has some methods to filter the input values:
 :method:`Symfony\\Component\\HttpFoundation\\ParameterBag::getString`
     Returns the parameter value as a string;
 
-.. versionadded:: 6.3
-
-    The ``ParameterBag::getEnum()`` and ``ParameterBag::getString()`` methods
-    were introduced in Symfony 6.3.
-
 :method:`Symfony\\Component\\HttpFoundation\\ParameterBag::filter`
     Filters the parameter by using the PHP :phpfunction:`filter_var` function.
-
-    .. deprecated:: 6.3
-
-        Ignoring invalid values when using ``filter()`` is deprecated and will throw
-        a :class:`Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException`
-        in Symfony 7.0. You can use the ``FILTER_NULL_ON_FAILURE`` flag to keep
-        ignoring them.
+    If invalid values are found, a
+    :class:`Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException`
+    is thrown. The ``FILTER_NULL_ON_FAILURE`` flag can be used to ignore invalid
+    values.
 
 All getters take up to two arguments: the first one is the parameter name
 and the second one is the default value to return if the parameter does not
@@ -223,11 +215,6 @@ wrapping this data::
 
     $data = $request->getPayload();
 
-.. versionadded:: 6.3
-
-    The :method:`Symfony\\Component\\HttpFoundation\\Request::getPayload`
-    method was introduced in Symfony 6.3.
-
 Identifying a Request
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -375,6 +362,25 @@ analysis purposes. Use the ``anonymize()`` method from the
     $anonymousIpv6 = IpUtils::anonymize($ipv6);
     // $anonymousIpv6 = '2a01:198:603:10::'
 
+If you need even more anonymization, you can use the second and third parameters
+of the ``anonymize()`` method to specify the number of bytes that should be
+anonymized depending on the IP address format::
+
+    $ipv4 = '123.234.235.236';
+    $anonymousIpv4 = IpUtils::anonymize($ipv4, 3);
+    // $anonymousIpv4 = '123.0.0.0'
+
+    $ipv6 = '2a01:198:603:10:396e:4789:8e99:890f';
+    // (you must define the second argument (bytes to anonymize in IPv4 addresses)
+    // even when you are only anonymizing IPv6 addresses)
+    $anonymousIpv6 = IpUtils::anonymize($ipv6, 3, 10);
+    // $anonymousIpv6 = '2a01:198:603::'
+
+.. versionadded:: 7.2
+
+    The ``v4Bytes`` and ``v6Bytes`` parameters of the ``anonymize()`` method
+    were introduced in Symfony 7.2.
+
 Check If an IP Belongs to a CIDR Subnet
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -410,10 +416,6 @@ use the ``isPrivateIp()`` method from the
     $isPrivate = IpUtils::isPrivateIp($ipv6);
     // $isPrivate = false
 
-.. versionadded:: 6.3
-
-    The ``isPrivateIp()`` method was introduced in Symfony 6.3.
-
 Matching a Request Against a Set of Rules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -423,17 +425,18 @@ address, it uses a certain HTTP method, etc.):
 
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\AttributesRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\ExpressionRequestMatcher`
+* :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\HeaderRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\HostRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\IpsRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\IsJsonRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\MethodRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\PathRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\PortRequestMatcher`
+* :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\QueryParameterRequestMatcher`
 * :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher\\SchemeRequestMatcher`
 
 You can use them individually or combine them using the
-:class:`Symfony\\Component\\HttpFoundation\\ChainRequestMatcher`
-class::
+:class:`Symfony\\Component\\HttpFoundation\\ChainRequestMatcher` class::
 
     use Symfony\Component\HttpFoundation\ChainRequestMatcher;
     use Symfony\Component\HttpFoundation\RequestMatcher\HostRequestMatcher;
@@ -456,6 +459,11 @@ class::
         // ...
     }
 
+.. versionadded:: 7.1
+
+    The ``HeaderRequestMatcher`` and ``QueryParameterRequestMatcher`` were
+    introduced in Symfony 7.1.
+
 Accessing other Data
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -555,12 +563,6 @@ your application to see which exceptions are thrown in listeners of the
 more about it in
 :ref:`the dedicated section about Kernel events <http-kernel-creating-listener>`.
 
-.. versionadded:: 6.4
-
-    The ``$flush`` parameter of the
-    :method:`Symfony\\Component\\HttpFoundation\\Response::send` method
-    was introduced in Symfony 6.4.
-
 Setting Cookies
 ~~~~~~~~~~~~~~~
 
@@ -601,11 +603,6 @@ It is possible to define partitioned cookies, also known as `CHIPS`_, by using t
     // you can also set the partitioned argument to true when using the `create()` factory method
     $cookie = Cookie::create('name', 'value', partitioned: true);
 
-.. versionadded:: 6.4
-
-    The :method:`Symfony\\Component\\HttpFoundation\\Cookie::withPartitioned`
-    method was introduced in Symfony 6.4.
-
 Managing the HTTP Cache
 ~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -654,11 +651,6 @@ call::
         'etag'             => 'abcdef',
     ]);
 
-.. versionadded:: 6.1
-
-    The ``stale_if_error`` and ``stale_while_revalidate`` options were
-    introduced in Symfony 6.1.
-
 To check if the Response validators (``ETag``, ``Last-Modified``) match a
 conditional value specified in the client Request, use the
 :method:`Symfony\\Component\\HttpFoundation\\Response::isNotModified`
@@ -689,8 +681,19 @@ Streaming a Response
 ~~~~~~~~~~~~~~~~~~~~
 
 The :class:`Symfony\\Component\\HttpFoundation\\StreamedResponse` class allows
-you to stream the Response back to the client. The response content is
-represented by a PHP callable instead of a string::
+you to stream the Response back to the client. The response content can be
+represented by a string iterable::
+
+    use Symfony\Component\HttpFoundation\StreamedResponse;
+
+    $chunks = ['Hello', ' World'];
+
+    $response = new StreamedResponse();
+    $response->setChunks($chunks);
+    $response->send();
+
+For most complex use cases, the response content can be instead represented by
+a PHP callable::
 
     use Symfony\Component\HttpFoundation\StreamedResponse;
 
@@ -718,13 +721,12 @@ represented by a PHP callable instead of a string::
         // disables FastCGI buffering in nginx only for this response
         $response->headers->set('X-Accel-Buffering', 'no');
 
-Streaming a JSON Response
-~~~~~~~~~~~~~~~~~~~~~~~~~
+.. versionadded:: 7.3
 
-.. versionadded:: 6.3
+    Support for using string iterables was introduced in Symfony 7.3.
 
-    The :class:`Symfony\\Component\\HttpFoundation\\StreamedJsonResponse` class was
-    introduced in Symfony 6.3.
+Streaming a JSON Response
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The :class:`Symfony\\Component\\HttpFoundation\\StreamedJsonResponse` allows to
 stream large JSON responses using PHP generators to keep the used resources low.
@@ -738,9 +740,9 @@ containing JSON serializable data::
 
     // any method or function returning a PHP Generator
     function loadArticles(): \Generator {
-         yield ['title' => 'Article 1'];
-         yield ['title' => 'Article 2'];
-         yield ['title' => 'Article 3'];
+        yield ['title' => 'Article 1'];
+        yield ['title' => 'Article 2'];
+        yield ['title' => 'Article 3'];
     };
 
     $response = new StreamedJsonResponse(
@@ -815,10 +817,6 @@ including generators::
         return new StreamedJsonResponse(loadArticles());
     }
 
-.. versionadded:: 6.4
-
-    The ``StreamedJsonResponse`` support of iterables was introduced in Symfony 6.4.
-
 .. _component-http-foundation-serving-files:
 
 Serving Files
@@ -896,6 +894,23 @@ It is possible to delete the file after the response is sent with the
 :method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::deleteFileAfterSend` method.
 Please note that this will not work when the ``X-Sendfile`` header is set.
 
+Alternatively, ``BinaryFileResponse`` supports instances of ``\SplTempFileObject``.
+This is useful when you want to serve a file that has been created in memory
+and that will be automatically deleted after the response is sent::
+
+    use Symfony\Component\HttpFoundation\BinaryFileResponse;
+
+    $file = new \SplTempFileObject();
+    $file->fwrite('Hello World');
+    $file->rewind();
+
+    $response = new BinaryFileResponse($file);
+
+.. versionadded:: 7.1
+
+    The support for ``\SplTempFileObject`` in ``BinaryFileResponse``
+    was introduced in Symfony 7.1.
+
 If the size of the served file is unknown (e.g. because it's being generated on the fly,
 or because a PHP stream filter is registered on it, etc.), you can pass a ``Stream``
 instance to ``BinaryFileResponse``. This will disable ``Range`` and ``Content-Length``
diff --git a/components/http_kernel.rst b/components/http_kernel.rst
index 91643086a18..62d1e92d89b 100644
--- a/components/http_kernel.rst
+++ b/components/http_kernel.rst
@@ -261,18 +261,6 @@ on the request's information.
     b) A new instance of your controller class is instantiated with no
        constructor arguments.
 
-    c) If the controller implements :class:`Symfony\\Component\\DependencyInjection\\ContainerAwareInterface`,
-       ``setContainer()`` is called on the controller object and the container
-       is passed to it. This step is also specific to the  :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver`
-       sub-class used by the Symfony Framework.
-
-.. deprecated:: 6.4
-
-    :class:`Symfony\\Component\\DependencyInjection\\ContainerAwareInterface` and
-    :class:`Symfony\\Component\\DependencyInjection\\ContainerAwareTrait` are
-    deprecated since Symfony 6.4. Dependency injection should be used instead to
-    access the service container.
-
 .. _component-http-kernel-kernel-controller:
 
 3) The ``kernel.controller`` Event
@@ -293,10 +281,6 @@ Another typical use-case for this event is to retrieve the attributes from
 the controller using the :method:`Symfony\\Component\\HttpKernel\\Event\\ControllerEvent::getAttributes`
 method. See the Symfony section below for some examples.
 
-.. versionadded:: 6.2
-
-    The ``ControllerEvent::getAttributes()`` method was introduced in Symfony 6.2.
-
 Listeners to this event can also change the controller callable completely
 by calling :method:`ControllerEvent::setController <Symfony\\Component\\HttpKernel\\Event\\ControllerEvent::setController>`
 on the event object that's passed to listeners on this event.
@@ -356,13 +340,6 @@ of arguments that should be passed when executing that callable.
     ``ValueResolverInterface`` yourself and passing this to the
     ``ArgumentResolver``, you can extend this functionality.
 
-    .. versionadded:: 6.2
-
-        The ``ValueResolverInterface`` was introduced in Symfony 6.2. Prior to
-        6.2, you had to use the
-        :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`,
-        which defines different methods.
-
 .. _component-http-kernel-calling-controller:
 
 5) Calling the Controller
@@ -543,6 +520,17 @@ comes with an :class:`Symfony\\Component\\HttpKernel\\EventListener\\ErrorListen
 which if you choose to use, will do this and more by default (see the sidebar
 below for more details).
 
+The :class:`Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent` exposes the
+:method:`Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent::isKernelTerminating`
+method, which you can use to determine if the kernel is currently terminating
+at the moment the exception was thrown.
+
+.. versionadded:: 7.1
+
+    The
+    :method:`Symfony\\Component\\HttpKernel\\Event\\ExceptionEvent::isKernelTerminating`
+    method was introduced in Symfony 7.1.
+
 .. note::
 
     When setting a response for the ``kernel.exception`` event, the propagation
diff --git a/components/intl.rst b/components/intl.rst
index f69284c1a0e..ba3cbdcb959 100644
--- a/components/intl.rst
+++ b/components/intl.rst
@@ -28,7 +28,6 @@ This component provides the following ICU data:
 * `Locales`_
 * `Currencies`_
 * `Timezones`_
-* `Emoji Transliteration`_
 
 Language and Script Names
 ~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -203,10 +202,6 @@ numeric country codes::
     $exists = Countries::numericCodeExists('250');
     // => true
 
-.. versionadded:: 6.4
-
-    The support for numeric country codes was introduced in Symfony 6.4.
-
 Locales
 ~~~~~~~
 
@@ -390,61 +385,22 @@ to catching the exception, you can also check if a given timezone ID is valid::
 Emoji Transliteration
 ~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.2
-
-    The Emoji transliteration feature was introduced in Symfony 6.2.
-
-The ``EmojiTransliterator`` class provides a utility to translate emojis into
-their textual representation in all languages based on the `Unicode CLDR dataset`_::
-
-    use Symfony\Component\Intl\Transliterator\EmojiTransliterator;
-
-    // describe emojis in English
-    $transliterator = EmojiTransliterator::create('en');
-    $transliterator->transliterate('Menus with 🍕 or 🍝');
-    // => 'Menus with pizza or spaghetti'
-
-    // describe emojis in Ukrainian
-    $transliterator = EmojiTransliterator::create('uk');
-    $transliterator->transliterate('Menus with 🍕 or 🍝');
-    // => 'Menus with піца or спагеті'
-
-The ``EmojiTransliterator`` class also provides two extra catalogues: ``github``
-and ``slack`` that converts any emojis to the corresponding short code in those
-platforms::
+Symfony provides utilities to translate emojis into their textual representation
+in all languages. Read the documentation about :ref:`emoji transliteration <emoji-transliteration>`
+to learn more about this feature.
 
-    use Symfony\Component\Intl\Transliterator\EmojiTransliterator;
-
-    // describe emojis in Slack short code
-    $transliterator = EmojiTransliterator::create('slack');
-    $transliterator->transliterate('Menus with 🥗 or 🧆');
-    // => 'Menus with :green_salad: or :falafel:'
-
-    // describe emojis in Github short code
-    $transliterator = EmojiTransliterator::create('github');
-    $transliterator->transliterate('Menus with 🥗 or 🧆');
-    // => 'Menus with :green_salad: or :falafel:'
-
-.. tip::
-
-    Combine this emoji transliterator with the :ref:`Symfony String slugger <string-slugger-emoji>`
-    to improve the slugs of contents that include emojis (e.g. for URLs).
+Disk Space
+----------
 
-The data needed to store the transliteration of all emojis (~5,000) into all
-languages take a considerable disk space. If you need to save disk space (e.g.
-because you deploy to some service with tight size constraints), run this command
-(e.g. as an automated script after ``composer install``) to compress the internal
-Symfony emoji data files using the PHP ``zlib`` extension:
+If you need to save disk space (e.g. because you deploy to some service with tight size
+constraints), run this command (e.g. as an automated script after ``composer install``) to compress the
+internal Symfony Intl data files using the PHP ``zlib`` extension:
 
 .. code-block:: terminal
 
     # adjust the path to the 'compress' binary based on your application installation
     $ php ./vendor/symfony/intl/Resources/bin/compress
 
-.. versionadded:: 6.3
-
-    The ``compress`` binary was introduced in Symfony 6.3.
-
 Learn more
 ----------
 
@@ -467,4 +423,3 @@ Learn more
 .. _`daylight saving time (DST)`: https://en.wikipedia.org/wiki/Daylight_saving_time
 .. _`ISO 639-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_639-1
 .. _`ISO 639-2 alpha-3 (2T)`: https://en.wikipedia.org/wiki/ISO_639-2
-.. _`Unicode CLDR dataset`: https://github.com/unicode-org/cldr
diff --git a/components/json_path.rst b/components/json_path.rst
new file mode 100644
index 00000000000..9db8e48885e
--- /dev/null
+++ b/components/json_path.rst
@@ -0,0 +1,330 @@
+The JsonPath Component
+======================
+
+.. versionadded:: 7.3
+
+    The JsonPath component was introduced in Symfony 7.3 as an
+    :doc:`experimental feature </contributing/code/experimental>`.
+
+The JsonPath component lets you query and extract data from JSON structures.
+It implements the `RFC 9535 – JSONPath`_ standard, allowing you to navigate
+complex JSON data.
+
+Similar to the :doc:`DomCrawler component </components/dom_crawler>`, which lets
+you navigate and query HTML or XML documents with XPath, the JsonPath component
+offers the same convenience for traversing and searching JSON structures through
+JSONPath expressions. The component also provides an abstraction layer for data
+extraction.
+
+Installation
+------------
+
+You can install the component in your project using Composer:
+
+.. code-block:: terminal
+
+    $ composer require symfony/json-path
+
+.. include:: /components/require_autoload.rst.inc
+
+Usage
+-----
+
+To start querying a JSON document, first create a :class:`Symfony\\Component\\JsonPath\\JsonCrawler`
+object from a JSON string. The following examples use this sample "bookstore"
+JSON data::
+
+    use Symfony\Component\JsonPath\JsonCrawler;
+
+    $json = <<<'JSON'
+    {
+        "store": {
+            "book": [
+                {
+                    "category": "reference",
+                    "author": "Nigel Rees",
+                    "title": "Sayings of the Century",
+                    "price": 8.95
+                },
+                {
+                    "category": "fiction",
+                    "author": "Evelyn Waugh",
+                    "title": "Sword of Honour",
+                    "price": 12.99
+                },
+                {
+                    "category": "fiction",
+                    "author": "Herman Melville",
+                    "title": "Moby Dick",
+                    "isbn": "0-553-21311-3",
+                    "price": 8.99
+                },
+                {
+                    "category": "fiction",
+                    "author": "John Ronald Reuel Tolkien",
+                    "title": "The Lord of the Rings",
+                    "isbn": "0-395-19395-8",
+                    "price": 22.99
+                }
+            ],
+            "bicycle": {
+                "color": "red",
+                "price": 399
+            }
+        }
+    }
+    JSON;
+
+    $crawler = new JsonCrawler($json);
+
+Once you have the crawler instance, use its :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find`
+method to start querying the data. This method returns an array of matching values.
+
+Querying with Expressions
+-------------------------
+
+The primary way to query the JSON is by passing a JSONPath expression string
+to the :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method.
+
+Accessing a Specific Property
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use dot notation for object keys and square brackets for array indices. The root
+of the document is represented by ``$``::
+
+    // get the title of the first book in the store
+    $titles = $crawler->find('$.store.book[0].title');
+
+    // $titles is ['Sayings of the Century']
+
+Dot notation is the default, but JSONPath provides other syntaxes for cases
+where it doesn't work. Use bracket notation (``['...']``) when a key contains
+spaces or special characters::
+
+    // this is equivalent to the previous example
+    $titles = $crawler->find('$["store"]["book"][0]["title"]');
+
+    // this expression requires brackets because some keys use dots or spaces
+    $titles = $crawler->find('$["store"]["book collection"][0]["title.original"]');
+
+    // you can combine both notations
+    $titles = $crawler->find('$["store"].book[0].title');
+
+Searching with the Descendant Operator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The descendant operator (``..``) recursively searches for a given key, allowing
+you to find values without specifying the full path::
+
+    // get all authors from anywhere in the document
+    $authors = $crawler->find('$..author');
+
+    // $authors is ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'John Ronald Reuel Tolkien']
+
+Filtering Results
+~~~~~~~~~~~~~~~~~
+
+JSONPath includes a filter syntax (``?(expression)``) to select items based on
+a condition. The current item within the filter is referenced by ``@``::
+
+    // get all books with a price less than 10
+    $cheapBooks = $crawler->find('$.store.book[?(@.price < 10)]');
+
+Building Queries Programmatically
+---------------------------------
+
+For more dynamic or complex query building, use the fluent API provided
+by the :class:`Symfony\\Component\\JsonPath\\JsonPath` class. This lets you
+construct a query object step by step. The ``JsonPath`` object can then be passed
+to the crawler's :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method.
+
+The main advantage of the programmatic builder is that it automatically handles
+escaping of keys and values, preventing syntax errors::
+
+    use Symfony\Component\JsonPath\JsonPath;
+
+    $path = (new JsonPath())
+        ->key('store') // selects the 'store' key
+        ->key('book')  // then the 'book' key
+        ->index(1);    // then the second item (indexes start at 0)
+
+    // the created $path object is equivalent to the string '$["store"]["book"][1]'
+    $book = $crawler->find($path);
+
+    // $book contains the book object for "Sword of Honour"
+
+The :class:`Symfony\\Component\\JsonPath\\JsonPath` class provides several
+methods to build your query:
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::key`
+  Adds a key selector. The key name is properly escaped::
+
+      // creates the path '$["key\"with\"quotes"]'
+      $path = (new JsonPath())->key('key"with"quotes');
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::deepScan`
+  Adds the descendant operator ``..`` to perform a recursive search from the
+  current point in the path::
+
+      // get all prices in the store: '$["store"]..["price"]'
+      $path = (new JsonPath())->key('store')->deepScan()->key('price');
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::all`
+  Adds the wildcard operator ``[*]`` to select all items in an array or object::
+
+        // creates the path '$["store"]["book"][*]'
+        $path = (new JsonPath())->key('store')->key('book')->all();
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::index`
+  Adds an array index selector. Index numbers start at ``0``.
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::first` /
+  :method:`Symfony\\Component\\JsonPath\\JsonPath::last`
+  Shortcuts for ``index(0)`` and ``index(-1)`` respectively::
+
+      // get the last book: '$["store"]["book"][-1]'
+      $path = (new JsonPath())->key('store')->key('book')->last();
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::slice`
+  Adds an array slice selector ``[start:end:step]``::
+
+      // get books from index 1 up to (but not including) index 3
+      // creates the path '$["store"]["book"][1:3]'
+      $path = (new JsonPath())->key('store')->key('book')->slice(1, 3);
+
+      // get every second book from the first four books
+      // creates the path '$["store"]["book"][0:4:2]'
+      $path = (new JsonPath())->key('store')->key('book')->slice(0, 4, 2);
+
+* :method:`Symfony\\Component\\JsonPath\\JsonPath::filter`
+  Adds a filter expression. The expression string is the part that goes inside
+  the ``?()`` syntax::
+
+      // get expensive books: '$["store"]["book"][?(@.price > 20)]'
+      $path = (new JsonPath())
+          ->key('store')
+          ->key('book')
+          ->filter('@.price > 20');
+
+Advanced Querying
+-----------------
+
+For a complete overview of advanced operators like wildcards and functions within
+filters, refer to the `Querying with Expressions`_ section above. All these
+features are supported and can be combined with the programmatic builder when
+appropriate (e.g., inside a ``filter()`` expression).
+
+Testing with JSON Assertions
+----------------------------
+
+The component provides a set of PHPUnit assertions to make testing JSON data
+more convenient. Use the :class:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait`
+in your test class::
+
+    use PHPUnit\Framework\TestCase;
+    use Symfony\Component\JsonPath\Test\JsonPathAssertionsTrait;
+
+    class MyTest extends TestCase
+    {
+        use JsonPathAssertionsTrait;
+
+        public function testSomething(): void
+        {
+            $json = '{"books": [{"title": "A"}, {"title": "B"}]}';
+
+            self::assertJsonPathCount(2, '$.books[*]', $json);
+        }
+    }
+
+The trait provides the following assertion methods:
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathCount`
+  Asserts that the number of elements found by the JSONPath expression matches
+  an expected count::
+
+      $json = '{"a": [1, 2, 3]}';
+      self::assertJsonPathCount(3, '$.a[*]', $json);
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathEquals`
+  Asserts that the result of a JSONPath expression is equal to an expected
+  value. The comparison uses ``==`` (type coercion) instead of ``===``::
+
+      $json = '{"a": [1, 2, 3]}';
+
+      // passes because "1" == 1
+      self::assertJsonPathEquals(['1'], '$.a[0]', $json);
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathNotEquals`
+  Asserts that the result of a JSONPath expression is not equal to an expected
+  value. The comparison uses ``!=`` (type coercion) instead of ``!==``::
+
+      $json = '{"a": [1, 2, 3]}';
+      self::assertJsonPathNotEquals([42], '$.a[0]', $json);
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathSame`
+  Asserts that the result of a JSONPath expression is identical (``===``) to an
+  expected value. This is a strict comparison and does not perform type
+  coercion::
+
+      $json = '{"a": [1, 2, 3]}';
+
+      // fails because "1" !== 1
+      // self::assertJsonPathSame(['1'], '$.a[0]', $json);
+
+      self::assertJsonPathSame([1], '$.a[0]', $json);
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathNotSame`
+  Asserts that the result of a JSONPath expression is not identical (``!==``) to
+  an expected value::
+
+      $json = '{"a": [1, 2, 3]}';
+      self::assertJsonPathNotSame(['1'], '$.a[0]', $json);
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathContains`
+  Asserts that a given value is found within the array of results from the
+  JSONPath expression::
+
+      $json = '{"tags": ["php", "symfony", "json"]}';
+      self::assertJsonPathContains('symfony', '$.tags[*]', $json);
+
+* :method:`Symfony\\Component\\JsonPath\\Test\\JsonPathAssertionsTrait::assertJsonPathNotContains`
+  Asserts that a given value is NOT found within the array of results from the
+  JSONPath expression::
+
+      $json = '{"tags": ["php", "symfony", "json"]}';
+      self::assertJsonPathNotContains('java', '$.tags[*]', $json);
+
+Error Handling
+--------------
+
+The component throws specific exceptions for invalid input or queries:
+
+* :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidArgumentException`:
+  Thrown if the input to the ``JsonCrawler`` constructor is not a valid JSON string;
+* :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidJsonStringInputException`:
+  Thrown during a ``find()`` call if the JSON string is malformed (e.g., syntax error);
+* :class:`Symfony\\Component\\JsonPath\\Exception\\JsonCrawlerException`:
+  Thrown for errors within the JsonPath expression itself, such as using an
+  unknown function
+
+Example of handling errors::
+
+    use Symfony\Component\JsonPath\Exception\InvalidJsonStringInputException;
+    use Symfony\Component\JsonPath\Exception\JsonCrawlerException;
+
+    try {
+        // the following line contains malformed JSON
+        $crawler = new JsonCrawler('{"store": }');
+        $crawler->find('$..*');
+    } catch (InvalidJsonStringInputException $e) {
+        // ... handle error
+    }
+
+    try {
+        // the following line contains an invalid query
+        $crawler->find('$.store.book[?unknown_function(@.price)]');
+    } catch (JsonCrawlerException $e) {
+        // ... handle error
+    }
+
+.. _`RFC 9535 – JSONPath`: https://datatracker.ietf.org/doc/html/rfc9535
diff --git a/components/ldap.rst b/components/ldap.rst
index f5a142ced9f..e52a341986c 100644
--- a/components/ldap.rst
+++ b/components/ldap.rst
@@ -74,6 +74,19 @@ distinguished name (DN) and the password of a user::
 
     When the LDAP server allows unauthenticated binds, a blank password will always be valid.
 
+You can also use the :method:`Symfony\\Component\\Ldap\\Ldap::saslBind` method
+for binding to an LDAP server using `SASL`_::
+
+    // this method defines other optional arguments like $mech, $realm, $authcId, etc.
+    $ldap->saslBind($dn, $password);
+
+After binding to the LDAP server, you can use the :method:`Symfony\\Component\\Ldap\\Ldap::whoami`
+method to get the distinguished name (DN) of the authenticated and authorized user.
+
+.. versionadded:: 7.2
+
+    The ``saslBind()`` and ``whoami()`` methods were introduced in Symfony 7.2.
+
 Once bound (or if you enabled anonymous authentication on your
 LDAP server), you may query the LDAP server using the
 :method:`Symfony\\Component\\Ldap\\Ldap::query` method::
@@ -183,3 +196,5 @@ Possible operation types are ``LDAP_MODIFY_BATCH_ADD``, ``LDAP_MODIFY_BATCH_REMO
 ``LDAP_MODIFY_BATCH_REMOVE_ALL``, ``LDAP_MODIFY_BATCH_REPLACE``. Parameter
 ``$values`` must be ``NULL`` when using ``LDAP_MODIFY_BATCH_REMOVE_ALL``
 operation type.
+
+.. _`SASL`: https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer
diff --git a/components/lock.rst b/components/lock.rst
index fb7efeb2b77..e9fe61ecd1a 100644
--- a/components/lock.rst
+++ b/components/lock.rst
@@ -403,8 +403,14 @@ Store                                                       Scope   Blocking  Ex
 
 .. tip::
 
-    A special ``InMemoryStore`` is available for saving locks in memory during
-    a process, and can be useful for testing.
+    Symfony includes two other special stores that are mostly useful for testing:
+
+    * ``InMemoryStore`` (``LOCK_DSN=in-memory``), which saves locks in memory during a process;
+    * ``NullStore`` (``LOCK_DSN=null``) which doesn't persist anything.
+
+.. versionadded:: 7.2
+
+    The :class:`Symfony\\Component\\Lock\\Store\\NullStore` was introduced in Symfony 7.2.
 
 .. _lock-store-flock:
 
@@ -473,21 +479,15 @@ avoid stalled locks::
 
 The ``MongoDbStore`` takes the following ``$options`` (depending on the first parameter type):
 
-==============  ================================================================================================
-Option          Description
-==============  ================================================================================================
-gcProbability   Should a TTL Index be created expressed as a probability from 0.0 to 1.0 (Defaults to ``0.001``)
-gcProbablity    Same as ``gcProbability``, see the deprecation note below
-database        The name of the database
-collection      The name of the collection
-uriOptions      Array of URI options for `MongoDBClient::__construct`_
-driverOptions   Array of driver options for `MongoDBClient::__construct`_
-=============   ================================================================================================
-
-.. deprecated:: 6.3
-
-    The ``gcProbablity`` option (notice the typo in its name) is deprecated since
-    Symfony 6.3, use the ``gcProbability`` option instead.
+=============  ================================================================================================
+Option         Description
+=============  ================================================================================================
+gcProbability  Should a TTL Index be created expressed as a probability from 0.0 to 1.0 (Defaults to ``0.001``)
+database       The name of the database
+collection     The name of the collection
+uriOptions     Array of URI options for `MongoDBClient::__construct`_
+driverOptions  Array of driver options for `MongoDBClient::__construct`_
+=============  ================================================================================================
 
 When the first parameter is a:
 
@@ -561,11 +561,6 @@ the command:
 
     $ php bin/console make:migration
 
-.. versionadded:: 6.3
-
-    The automatic table generation when running the ``make:migration`` command
-    was introduced in Symfony 6.3.
-
 If you prefer to create the table yourself and it has not already been created, you can
 create this table explicitly by calling the
 :method:`Symfony\\Component\\Lock\\Store\\DoctrineDbalStore::createTable` method.
@@ -617,14 +612,10 @@ store locks and does not expire.
 RedisStore
 ~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    ``\Relay\Relay`` support was introduced in Symfony 6.3.
-
 The RedisStore saves locks on a Redis server, it requires a Redis connection
-implementing the ``\Redis``, ``\RedisArray``, ``\RedisCluster``, ``\Relay\Relay`` or
-``\Predis`` classes. This store does not support blocking, and expects a TTL to
-avoid stalled locks::
+implementing the ``\Redis``, ``\RedisArray``, ``\RedisCluster``, ``\Relay\Relay``,
+``\Relay\Cluster`` or ``\Predis`` classes. This store does not support blocking,
+and expects a TTL to avoid stalled locks::
 
     use Symfony\Component\Lock\Store\RedisStore;
 
@@ -633,6 +624,10 @@ avoid stalled locks::
 
     $store = new RedisStore($redis);
 
+.. versionadded:: 7.3
+
+    Support for ``Relay\Cluster`` was introduced in Symfony 7.3.
+
 .. _lock-store-semaphore:
 
 SemaphoreStore
diff --git a/components/messenger.rst b/components/messenger.rst
index fe3d2926714..a8ff1e5290e 100644
--- a/components/messenger.rst
+++ b/components/messenger.rst
@@ -167,11 +167,6 @@ Here are some important envelope stamps that are shipped with the Symfony Messen
   differentiate it from messages created "manually". You can learn more about it
   in the :doc:`Scheduler documentation </scheduler>`.
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\Messenger\\Stamp\\ScheduledStamp` was
-    introduced in Symfony 6.4.
-
 .. note::
 
     The :class:`Symfony\\Component\\Messenger\\Stamp\\ErrorDetailsStamp` stamp
diff --git a/components/options_resolver.rst b/components/options_resolver.rst
index 35e443d3d94..17ec46c2fc9 100644
--- a/components/options_resolver.rst
+++ b/components/options_resolver.rst
@@ -305,13 +305,21 @@ correctly. To validate the types of the options, call
 
             // specify multiple allowed types
             $resolver->setAllowedTypes('port', ['null', 'int']);
+            // if you prefer, you can also use the following equivalent syntax
+            $resolver->setAllowedTypes('port', 'int|null');
 
             // check all items in an array recursively for a type
             $resolver->setAllowedTypes('dates', 'DateTime[]');
             $resolver->setAllowedTypes('ports', 'int[]');
+            // the following syntax means "an array of integers or an array of strings"
+            $resolver->setAllowedTypes('endpoints', '(int|string)[]');
         }
     }
 
+.. versionadded:: 7.3
+
+    Defining type unions with the ``|`` syntax was introduced in Symfony 7.3.
+
 You can pass any type for which an ``is_<type>()`` function is defined in PHP.
 You may also pass fully qualified class or interface names (which is checked
 using ``instanceof``). Additionally, you can validate all items in an array
@@ -386,7 +394,7 @@ returns ``true`` for acceptable values and ``false`` for invalid values::
 
         // ...
         $resolver->setAllowedValues('transport', Validation::createIsValidCallable(
-            new Length(['min' => 10 ])
+            new Length(min: 10)
         ));
 
 In sub-classes, you can use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addAllowedValues`
@@ -654,7 +662,7 @@ default value::
 
         public function configureOptions(OptionsResolver $resolver): void
         {
-            $resolver->setDefault('spool', function (OptionsResolver $spoolResolver): void {
+            $resolver->setOptions('spool', function (OptionsResolver $spoolResolver): void {
                 $spoolResolver->setDefaults([
                     'type' => 'file',
                     'path' => '/path/to/spool',
@@ -678,6 +686,16 @@ default value::
         ],
     ]);
 
+.. deprecated:: 7.3
+
+    Defining nested options via :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setDefault`
+    is deprecated since Symfony 7.3. Use the :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::setOptions`
+    method instead, which also allows defining default values for prototyped options.
+
+.. versionadded:: 7.3
+
+    The ``setOptions()`` method was introduced in Symfony 7.3.
+
 Nested options also support required options, validation (type, value) and
 normalization of their values. If the default value of a nested option depends
 on another option defined in the parent level, add a second ``Options`` argument
@@ -690,7 +708,7 @@ to the closure to access to them::
         public function configureOptions(OptionsResolver $resolver): void
         {
             $resolver->setDefault('sandbox', false);
-            $resolver->setDefault('spool', function (OptionsResolver $spoolResolver, Options $parent): void {
+            $resolver->setOptions('spool', function (OptionsResolver $spoolResolver, Options $parent): void {
                 $spoolResolver->setDefaults([
                     'type' => $parent['sandbox'] ? 'memory' : 'file',
                     // ...
@@ -713,13 +731,13 @@ In same way, parent options can access to the nested options as normal arrays::
 
         public function configureOptions(OptionsResolver $resolver): void
         {
-            $resolver->setDefault('spool', function (OptionsResolver $spoolResolver): void {
+            $resolver->setOptions('spool', function (OptionsResolver $spoolResolver): void {
                 $spoolResolver->setDefaults([
                     'type' => 'file',
                     // ...
                 ]);
             });
-            $resolver->setDefault('profiling', function (Options $options): void {
+            $resolver->setOptions('profiling', function (Options $options): void {
                 return 'file' === $options['spool']['type'];
             });
         }
@@ -740,7 +758,7 @@ with ``host``, ``database``, ``user`` and ``password`` each.
 
 The best way to implement this is to define the ``connections`` option as prototype::
 
-    $resolver->setDefault('connections', function (OptionsResolver $connResolver): void {
+    $resolver->setOptions('connections', function (OptionsResolver $connResolver): void {
         $connResolver
             ->setPrototype(true)
             ->setRequired(['host', 'database'])
@@ -869,10 +887,6 @@ if an unknown option is passed. You can ignore not defined options by using the
         'version'  => '1.2.3'
     ]);
 
-.. versionadded:: 6.3
-
-    The ``ignoreUndefined()`` method was introduced in Symfony 6.3.
-
 Chaining Option Configurations
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst
index 5a2c508b68d..5ce4c003a11 100644
--- a/components/phpunit_bridge.rst
+++ b/components/phpunit_bridge.rst
@@ -291,10 +291,6 @@ Here is a summary that should help you pick the right configuration:
 Ignoring Deprecations
 .....................
 
-.. versionadded:: 6.1
-
-    The ``ignoreFile`` feature was introduced in Symfony 6.1.
-
 If your application has some deprecations that you can't fix for some reasons,
 you can tell Symfony to ignore them.
 
@@ -435,11 +431,6 @@ configuration file:
 Finally, if you want to avoid the bridge to force any locale, you can set the
 ``SYMFONY_PHPUNIT_LOCALE`` environment variable to ``0``.
 
-.. versionadded:: 6.4
-
-    The support for the ``SYMFONY_PHPUNIT_LOCALE`` environment variable was
-    introduced in Symfony 6.4.
-
 .. _write-assertions-about-deprecations:
 
 Write Assertions about Deprecations
@@ -579,10 +570,6 @@ allows you to mock the PHP's built-in time functions ``time()``, ``microtime()``
 function ``date()`` is mocked so it uses the mocked time if no timestamp is
 specified.
 
-.. versionadded:: 6.2
-
-    Support for mocking the ``hrtime()`` function was introduced in Symfony 6.2.
-
 Other functions with an optional timestamp parameter that defaults to ``time()``
 will still use the system time instead of the mocked time. This means that you
 may need to change some code in your tests. For example, instead of ``new DateTime()``,
@@ -779,10 +766,6 @@ reason, this component also provides mocks for these PHP functions:
 * :phpfunction:`trait_exists`
 * :phpfunction:`enum_exists`
 
-.. versionadded:: 6.3
-
-    The ``enum_exists`` function was introduced in Symfony 6.3.
-
 Use Case
 ~~~~~~~~
 
@@ -854,10 +837,6 @@ PHP 8.1 and later, calling ``class_exists`` on a enum will return ``true``.
 That's why calling ``ClassExistsMock::withMockedEnums()`` will also register the enum
 as a mocked class.
 
-.. versionadded:: 6.3
-
-    The ``enum_exists`` function was introduced in Symfony 6.3.
-
 Troubleshooting
 ---------------
 
diff --git a/components/process.rst b/components/process.rst
index 10e7e0777af..9c25c931510 100644
--- a/components/process.rst
+++ b/components/process.rst
@@ -114,6 +114,8 @@ You can configure the options passed to the ``other_options`` argument of
     and ``suppress_errors``) are only supported on Windows operating systems.
     Check out the `PHP documentation for proc_open()`_ before using them.
 
+.. _process-using-features-from-the-os-shell:
+
 Using Features From the OS Shell
 --------------------------------
 
@@ -418,10 +420,6 @@ instead::
 Executing a PHP Child Process with the Same Configuration
 ---------------------------------------------------------
 
-.. versionadded:: 6.4
-
-    The ``PhpSubprocess`` helper was introduced in Symfony 6.4.
-
 When you start a PHP process, it uses the default configuration defined in
 your ``php.ini`` file. You can bypass these options with the ``-d`` command line
 option. For example, if ``memory_limit`` is set to ``256M``, you can disable this
@@ -432,11 +430,14 @@ However, if you run the command via the Symfony ``Process`` class, PHP will use
 the settings defined in the ``php.ini`` file. You can solve this issue by using
 the :class:`Symfony\\Component\\Process\\PhpSubprocess` class to run the command::
 
+    use Symfony\Component\Console\Attribute\AsCommand;
+    use Symfony\Component\Console\Style\SymfonyStyle;
     use Symfony\Component\Process\Process;
 
-    class MyCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(SymfonyStyle $io): int
         {
             // the memory_limit (and any other config option) of this command is
             // the one defined in php.ini instead of the new values (optionally)
@@ -446,6 +447,8 @@ the :class:`Symfony\\Component\\Process\\PhpSubprocess` class to run the command
             // the memory_limit (and any other config option) of this command takes
             // into account the values (optionally) passed via the '-d' command option
             $childProcess = new PhpSubprocess(['bin/console', 'cache:pool:prune']);
+
+            return 0;
         }
     }
 
@@ -515,6 +518,20 @@ When running a program asynchronously, you can send it POSIX signals with the
     // will send a SIGKILL to the process
     $process->signal(SIGKILL);
 
+You can make the process ignore signals by using the
+:method:`Symfony\\Component\\Process\\Process::setIgnoredSignals`
+method. The given signals won't be propagated to the child process::
+
+    use Symfony\Component\Process\Process;
+
+    $process = new Process(['find', '/', '-name', 'rabbit']);
+    $process->setIgnoredSignals([SIGKILL, SIGUSR1]);
+
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\Process\\Process::setIgnoredSignals`
+    method was introduced in Symfony 7.1.
+
 Process Pid
 -----------
 
diff --git a/components/property_access.rst b/components/property_access.rst
index 9944ad05273..f608640fa9b 100644
--- a/components/property_access.rst
+++ b/components/property_access.rst
@@ -91,11 +91,6 @@ You can also use multi dimensional arrays::
 
     Right square brackets ``]`` don't need to be escaped in array keys.
 
-    .. versionadded:: 6.3
-
-        Escaping dots and left square brackets in a property path was
-        introduced in Symfony 6.3.
-
 Reading from Objects
 --------------------
 
@@ -238,10 +233,6 @@ is to mark all nullable properties with the nullsafe operator (``?``)::
     // no longer evaluated and null is returned immediately without throwing an exception
     var_dump($propertyAccessor->getValue($comment, 'person?.firstname')); // null
 
-.. versionadded:: 6.2
-
-    The ``?`` nullsafe operator was introduced in Symfony 6.2.
-
 .. _components-property-access-magic-get:
 
 Magic ``__get()`` Method
diff --git a/components/property_info.rst b/components/property_info.rst
index 238da6396ab..865a36c5941 100644
--- a/components/property_info.rst
+++ b/components/property_info.rst
@@ -183,6 +183,26 @@ for a property::
 
 See :ref:`components-property-info-type` for info about the ``Type`` class.
 
+Documentation Block
+~~~~~~~~~~~~~~~~~~~
+
+Extractors that implement :class:`Symfony\\Component\\PropertyInfo\\PropertyDocBlockExtractorInterface`
+can provide the full documentation block for a property as a string::
+
+    $docBlock = $propertyInfo->getDocBlock($class, $property);
+    /*
+        Example Result
+        --------------
+        string(79):
+            This is the subsequent paragraph in the DocComment.
+            It can span multiple lines.
+    */
+
+.. versionadded:: 7.1
+
+    The :class:`Symfony\\Component\\PropertyInfo\\PropertyDocBlockExtractorInterface`
+    interface was introduced in Symfony 7.1.
+
 .. _property-info-description:
 
 Description Information
@@ -229,12 +249,6 @@ works. It assumes camel case style method names following `PSR-1`_. For example,
 both ``myProperty`` and ``my_property`` properties are readable if there's a
 ``getMyProperty()`` method and writable if there's a ``setMyProperty()`` method.
 
-.. versionadded:: 6.4
-
-    In Symfony versions prior to 6.4, snake case properties (e.g. ``my_property``)
-    were not writable by camel case methods (e.g. ``setMyProperty()``). You had
-    to define method names with underscores (e.g. ``setMy_property()``).
-
 .. _property-info-initializable:
 
 Property Initializable Information
@@ -419,6 +433,12 @@ library is present::
     // Description information.
     $phpDocExtractor->getShortDescription($class, $property);
     $phpDocExtractor->getLongDescription($class, $property);
+    $phpDocExtractor->getDocBlock($class, $property);
+
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpDocExtractor::getDocBlock`
+    method was introduced in Symfony 7.1.
 
 PhpStanExtractor
 ~~~~~~~~~~~~~~~~
@@ -449,7 +469,18 @@ information from annotations of properties and methods, such as ``@var``,
     use App\Domain\Foo;
 
     $phpStanExtractor = new PhpStanExtractor();
+
+    // Type information.
     $phpStanExtractor->getTypesFromConstructor(Foo::class, 'bar');
+    // Description information.
+    $phpStanExtractor->getShortDescription($class, 'bar');
+    $phpStanExtractor->getLongDescription($class, 'bar');
+
+.. versionadded:: 7.3
+
+    The :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpStanExtractor::getShortDescription`
+    and :method:`Symfony\\Component\\PropertyInfo\\Extractor\\PhpStanExtractor::getLongDescription`
+    methods were introduced in Symfony 7.3.
 
 SerializerExtractor
 ~~~~~~~~~~~~~~~~~~~
@@ -474,20 +505,6 @@ with the ``property_info`` service in the Symfony Framework::
     // the `serializer_groups` option must be configured (may be set to null)
     $serializerExtractor->getProperties($class, ['serializer_groups' => ['mygroup']]);
 
-.. versionadded:: 6.4
-
-    The
-    :class:`Symfony\\Component\\Serializer\\Mapping\\Loader\\AttributeLoader`
-    was introduced in Symfony 6.4. Prior to this, the
-    :class:`Symfony\\Component\\Serializer\\Mapping\\Loader\\AnnotationLoader`
-    must be used.
-
-.. deprecated:: 6.4
-
-    The
-    :class:`Symfony\\Component\\Serializer\\Mapping\\Loader\\AnnotationLoader`
-    was deprecated in Symfony 6.4.
-
 If ``serializer_groups`` is set to ``null``, serializer groups metadata won't be
 checked but you will get only the properties considered by the Serializer
 Component (notably the ``#[Ignore]`` attribute is taken into account).
@@ -521,6 +538,8 @@ with the ``property_info`` service in the Symfony Framework::
     // Type information.
     $doctrineExtractor->getTypes($class, $property);
 
+.. _components-property-information-constructor-extractor:
+
 ConstructorExtractor
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -553,6 +572,7 @@ Creating Your Own Extractors
 
 You can create your own property information extractors by creating a
 class that implements one or more of the following interfaces:
+:class:`Symfony\\Component\\PropertyInfo\\Extractor\\ConstructorArgumentTypeExtractorInterface`,
 :class:`Symfony\\Component\\PropertyInfo\\PropertyAccessExtractorInterface`,
 :class:`Symfony\\Component\\PropertyInfo\\PropertyDescriptionExtractorInterface`,
 :class:`Symfony\\Component\\PropertyInfo\\PropertyListExtractorInterface`,
@@ -570,6 +590,11 @@ service by defining it as a service with one or more of the following
 * ``property_info.access_extractor`` if it provides access information.
 * ``property_info.initializable_extractor`` if it provides initializable information
   (it checks if a property can be initialized through the constructor).
+* ``property_info.constructor_extractor`` if it provides type information from the constructor argument.
+
+  .. versionadded:: 7.3
+
+      The ``property_info.constructor_extractor`` tag was introduced in Symfony 7.3.
 
 .. _`PSR-1`: https://www.php-fig.org/psr/psr-1/
 .. _`phpDocumentor Reflection`: https://github.com/phpDocumentor/ReflectionDocBlock
diff --git a/components/type_info.rst b/components/type_info.rst
new file mode 100644
index 00000000000..817c7f1d61a
--- /dev/null
+++ b/components/type_info.rst
@@ -0,0 +1,202 @@
+The TypeInfo Component
+======================
+
+The TypeInfo component extracts type information from PHP elements like properties,
+arguments and return types.
+
+This component provides:
+
+* A powerful ``Type`` definition that can handle unions, intersections, and generics
+  (and can be extended to support more types in the future);
+* A way to get types from PHP elements such as properties, method arguments,
+  return types, and raw strings.
+
+Installation
+------------
+
+.. code-block:: terminal
+
+    $ composer require symfony/type-info
+
+.. include:: /components/require_autoload.rst.inc
+
+Usage
+-----
+
+This component gives you a :class:`Symfony\\Component\\TypeInfo\\Type` object that
+represents the PHP type of anything you built or asked to resolve.
+
+There are two ways to use this component. First one is to create a type manually thanks
+to the :class:`Symfony\\Component\\TypeInfo\\Type` static methods as following::
+
+    use Symfony\Component\TypeInfo\Type;
+
+    Type::int();
+    Type::nullable(Type::string());
+    Type::generic(Type::object(Collection::class), Type::int());
+    Type::list(Type::bool());
+    Type::intersection(Type::object(\Stringable::class), Type::object(\Iterator::class));
+
+Many others methods are available and can be found
+in :class:`Symfony\\Component\\TypeInfo\\TypeFactoryTrait`.
+
+You can also use a generic method that detects the type automatically::
+
+    Type::fromValue(1.1);   // same as Type::float()
+    Type::fromValue('...'); // same as Type::string()
+    Type::fromValue(false); // same as Type::false()
+
+.. versionadded:: 7.3
+
+    The ``fromValue()`` method was introduced in Symfony 7.3.
+
+Resolvers
+~~~~~~~~~
+
+The second way to use the component is by using ``TypeInfo`` to resolve a type
+based on reflection or a simple string. This approach is designed for libraries
+that need a simple way to describe a class or anything with a type::
+
+    use Symfony\Component\TypeInfo\Type;
+    use Symfony\Component\TypeInfo\TypeResolver\TypeResolver;
+
+    class Dummy
+    {
+        public function __construct(
+            public int $id,
+        ) {
+        }
+    }
+
+    // Instantiate a new resolver
+    $typeResolver = TypeResolver::create();
+
+    // Then resolve types for any subject
+    $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type instance
+    $typeResolver->resolve('bool'); // returns a "bool" Type instance
+
+    // Types can be instantiated thanks to static factories
+    $type = Type::list(Type::nullable(Type::bool()));
+
+    // Type instances have several helper methods
+
+    // for collections, it returns the type of the item used as the key;
+    // in this example, the collection is a list, so it returns an "int" Type instance
+    $keyType = $type->getCollectionKeyType();
+
+    // you can chain the utility methods (e.g. to introspect the values of the collection)
+    // the following code will return true
+    $isValueNullable = $type->getCollectionValueType()->isNullable();
+
+Each of these calls will return you a ``Type`` instance that corresponds to the
+static method used. You can also resolve types from a string (as shown in the
+``bool`` parameter of the previous example)
+
+PHPDoc Parsing
+~~~~~~~~~~~~~~
+
+In many cases, you may not have cleanly typed properties or may need more precise
+type definitions provided by advanced PHPDoc. To achieve this, you can use a string
+resolver based on the PHPDoc annotations.
+
+First, run the command ``composer require phpstan/phpdoc-parser`` to install the
+PHP package required for string resolving. Then, follow these steps::
+
+    use Symfony\Component\TypeInfo\TypeResolver\TypeResolver;
+
+    class Dummy
+    {
+        public function __construct(
+            public int $id,
+            /** @var string[] $tags */
+            public array $tags,
+        ) {
+        }
+    }
+
+    $typeResolver = TypeResolver::create();
+    $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'id')); // returns an "int" Type
+    $typeResolver->resolve(new \ReflectionProperty(Dummy::class, 'tags')); // returns a collection with "int" as key and "string" as values Type
+
+Advanced Usages
+~~~~~~~~~~~~~~~
+
+The TypeInfo component provides various methods to manipulate and check types,
+depending on your needs.
+
+**Identify** a type::
+
+    // define a simple integer type
+    $type = Type::int();
+    // check if the type matches a specific identifier
+    $type->isIdentifiedBy(TypeIdentifier::INT);    // true
+    $type->isIdentifiedBy(TypeIdentifier::STRING); // false
+
+    // define a union type (equivalent to PHP's int|string)
+    $type = Type::union(Type::string(), Type::int());
+    // now the second check is true because the union type contains the string type
+    $type->isIdentifiedBy(TypeIdentifier::INT);    // true
+    $type->isIdentifiedBy(TypeIdentifier::STRING); // true
+
+    class DummyParent {}
+    class Dummy extends DummyParent implements DummyInterface {}
+
+    // define an object type
+    $type = Type::object(Dummy::class);
+
+    // check if the type is an object or matches a specific class
+    $type->isIdentifiedBy(TypeIdentifier::OBJECT); // true
+    $type->isIdentifiedBy(Dummy::class);           // true
+    // check if it inherits/implements something
+    $type->isIdentifiedBy(DummyParent::class);     // true
+    $type->isIdentifiedBy(DummyInterface::class);  // true
+
+Checking if a type **accepts a value**::
+
+    $type = Type::int();
+    // check if the type accepts a given value
+    $type->accepts(123); // true
+    $type->accepts('z'); // false
+
+    $type = Type::union(Type::string(), Type::int());
+    // now the second check is true because the union type accepts either an int or a string value
+    $type->accepts(123); // true
+    $type->accepts('z'); // true
+
+.. versionadded:: 7.3
+
+    The :method:`Symfony\\Component\\TypeInfo\\Type::accepts`
+    method was introduced in Symfony 7.3.
+
+Using callables for **complex checks**::
+
+    class Foo
+    {
+        private int $integer;
+        private string $string;
+        private ?float $float;
+    }
+
+    $reflClass = new \ReflectionClass(Foo::class);
+
+    $resolver = TypeResolver::create();
+    $integerType = $resolver->resolve($reflClass->getProperty('integer'));
+    $stringType = $resolver->resolve($reflClass->getProperty('string'));
+    $floatType = $resolver->resolve($reflClass->getProperty('float'));
+
+    // define a callable to validate non-nullable number types
+    $isNonNullableNumber = function (Type $type): bool {
+        if ($type->isNullable()) {
+            return false;
+        }
+
+        if ($type->isIdentifiedBy(TypeIdentifier::INT) || $type->isIdentifiedBy(TypeIdentifier::FLOAT)) {
+            return true;
+        }
+
+        return false;
+    };
+
+    $integerType->isSatisfiedBy($isNonNullableNumber); // true
+    $stringType->isSatisfiedBy($isNonNullableNumber);  // false
+    $floatType->isSatisfiedBy($isNonNullableNumber);   // false
diff --git a/components/uid.rst b/components/uid.rst
index 4b6938e98d2..b4083765436 100644
--- a/components/uid.rst
+++ b/components/uid.rst
@@ -144,10 +144,6 @@ implementation-specific, and no particular format should be assumed::
     $uuid = Uuid::v8('d9e7a184-5d5b-11ea-a62a-3499710062d0');
     // $uuid is an instance of Symfony\Component\Uid\UuidV8
 
-.. versionadded:: 6.2
-
-    UUID versions 7 and 8 were introduced in Symfony 6.2.
-
 If your UUID value is already generated in another format, use any of the
 following methods to create a ``Uuid`` object from it::
 
@@ -168,10 +164,10 @@ configure the behavior of the factory using configuration files::
         # config/packages/uid.yaml
         framework:
             uid:
-                default_uuid_version: 6
+                default_uuid_version: 7
                 name_based_uuid_version: 5
                 name_based_uuid_namespace: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
-                time_based_uuid_version: 6
+                time_based_uuid_version: 7
                 time_based_uuid_node: 121212121212
 
     .. code-block:: xml
@@ -187,10 +183,10 @@ configure the behavior of the factory using configuration files::
 
             <framework:config>
                 <framework:uid
-                    default_uuid_version="6"
+                    default_uuid_version="7"
                     name_based_uuid_version="5"
                     name_based_uuid_namespace="6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-                    time_based_uuid_version="6"
+                    time_based_uuid_version="7"
                     time_based_uuid_node="121212121212"
                 />
             </framework:config>
@@ -209,10 +205,10 @@ configure the behavior of the factory using configuration files::
 
             $container->extension('framework', [
                 'uid' => [
-                    'default_uuid_version' => 6,
+                    'default_uuid_version' => 7,
                     'name_based_uuid_version' => 5,
                     'name_based_uuid_namespace' => '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
-                    'time_based_uuid_version' => 6,
+                    'time_based_uuid_version' => 7,
                     'time_based_uuid_node' => 121212121212,
                 ],
             ]);
@@ -234,7 +230,7 @@ on the configuration you defined::
 
         public function generate(): void
         {
-            // This creates a UUID of the version given in the configuration file (v6 by default)
+            // This creates a UUID of the version given in the configuration file (v7 by default)
             $uuid = $this->uuidFactory->create();
 
             $nameBasedUuid = $this->uuidFactory->nameBased(/** ... */);
@@ -257,10 +253,31 @@ Use these methods to transform the UUID object into different bases::
     $uuid->toBase58();  // string(22) "TuetYWNHhmuSQ3xPoVLv9M"
     $uuid->toRfc4122(); // string(36) "d9e7a184-5d5b-11ea-a62a-3499710062d0"
     $uuid->toHex();     // string(34) "0xd9e7a1845d5b11eaa62a3499710062d0"
+    $uuid->toString();  // string(36) "d9e7a184-5d5b-11ea-a62a-3499710062d0"
 
-.. versionadded:: 6.2
+.. versionadded:: 7.1
 
-    The ``toHex()`` method was introduced in Symfony 6.2.
+    The ``toString()`` method was introduced in Symfony 7.1.
+
+You can also convert some UUID versions to others::
+
+    // convert V1 to V6 or V7
+    $uuid = Uuid::v1();
+
+    $uuid->toV6(); // returns a Symfony\Component\Uid\UuidV6 instance
+    $uuid->toV7(); // returns a Symfony\Component\Uid\UuidV7 instance
+
+    // convert V6 to V7
+    $uuid = Uuid::v6();
+
+    $uuid->toV7(); // returns a Symfony\Component\Uid\UuidV7 instance
+
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\Uid\\UuidV1::toV6`,
+    :method:`Symfony\\Component\\Uid\\UuidV1::toV7` and
+    :method:`Symfony\\Component\\Uid\\UuidV6::toV7`
+    methods were introduced in Symfony 7.1.
 
 Working with UUIDs
 ~~~~~~~~~~~~~~~~~~
@@ -299,6 +316,31 @@ UUID objects created with the ``Uuid`` class can use the following methods
     //   * int < 0 if $uuid1 is less than $uuid4
     $uuid1->compare($uuid4); // e.g. int(4)
 
+If you're working with different UUIDs format and want to validate them,
+you can use the ``$format`` parameter of the :method:`Symfony\\Component\\Uid\\Uuid::isValid`
+method to specify the UUID format you're expecting::
+
+    use Symfony\Component\Uid\Uuid;
+
+    $isValid = Uuid::isValid('90067ce4-f083-47d2-a0f4-c47359de0f97', Uuid::FORMAT_RFC_4122); // accept only RFC 4122 UUIDs
+    $isValid = Uuid::isValid('3aJ7CNpDMfXPZrCsn4Cgey', Uuid::FORMAT_BASE_32 | Uuid::FORMAT_BASE_58); // accept multiple formats
+
+The following constants are available:
+
+* ``Uuid::FORMAT_BINARY``
+* ``Uuid::FORMAT_BASE_32``
+* ``Uuid::FORMAT_BASE_58``
+* ``Uuid::FORMAT_RFC_4122``
+* ``Uuid::FORMAT_RFC_9562`` (equivalent to ``Uuid::FORMAT_RFC_4122``)
+
+You can also use the ``Uuid::FORMAT_ALL`` constant to accept any UUID format.
+By default, only the RFC 4122 format is accepted.
+
+.. versionadded:: 7.2
+
+    The ``$format`` parameter of the :method:`Symfony\\Component\\Uid\\Uuid::isValid`
+    method and the related constants were introduced in Symfony 7.2.
+
 Storing UUIDs in Databases
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -321,10 +363,6 @@ type, which converts to/from UUID objects automatically::
         // ...
     }
 
-.. versionadded:: 6.2
-
-    The ``UuidType::NAME`` constant was introduced in Symfony 6.2.
-
 There's also a Doctrine generator to help auto-generate UUID values for the
 entity primary keys::
 
@@ -471,10 +509,6 @@ Use these methods to transform the ULID object into different bases::
     $ulid->toRfc4122(); // string(36) "0171069d-593d-97d3-8b3e-23d06de5b308"
     $ulid->toHex();     // string(34) "0x0171069d593d97d38b3e23d06de5b308"
 
-.. versionadded:: 6.2
-
-    The ``toHex()`` method was introduced in Symfony 6.2.
-
 Working with ULIDs
 ~~~~~~~~~~~~~~~~~~
 
@@ -518,10 +552,6 @@ type, which converts to/from ULID objects automatically::
         // ...
     }
 
-.. versionadded:: 6.2
-
-    The ``UlidType::NAME`` constant was introduced in Symfony 6.2.
-
 There's also a Doctrine generator to help auto-generate ULID values for the
 entity primary keys::
 
diff --git a/components/validator.rst b/components/validator.rst
index 085c77a7946..12c61507257 100644
--- a/components/validator.rst
+++ b/components/validator.rst
@@ -36,7 +36,7 @@ characters long::
 
     $validator = Validation::createValidator();
     $violations = $validator->validate('Bernhard', [
-        new Length(['min' => 10]),
+        new Length(min: 10),
         new NotBlank(),
     ]);
 
diff --git a/components/validator/metadata.rst b/components/validator/metadata.rst
index e7df42413bc..782e1ee216f 100755
--- a/components/validator/metadata.rst
+++ b/components/validator/metadata.rst
@@ -24,7 +24,7 @@ the ``Author`` class has at least 3 characters::
             $metadata->addPropertyConstraint('firstName', new Assert\NotBlank());
             $metadata->addPropertyConstraint(
                 'firstName',
-                new Assert\Length(["min" => 3])
+                new Assert\Length(min: 3)
             );
         }
     }
@@ -55,9 +55,9 @@ Then, add the Validator component configuration to the class::
     {
         public static function loadValidatorMetadata(ClassMetadata $metadata): void
         {
-            $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue([
-                'message' => 'The password cannot match your first name',
-            ]));
+            $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue(
+                message: 'The password cannot match your first name',
+            ));
         }
     }
 
diff --git a/components/validator/resources.rst b/components/validator/resources.rst
index 32b8e26f8a8..7d6cd0e8e5d 100644
--- a/components/validator/resources.rst
+++ b/components/validator/resources.rst
@@ -42,10 +42,10 @@ In this example, the validation metadata is retrieved executing the
         public static function loadValidatorMetadata(ClassMetadata $metadata): void
         {
             $metadata->addPropertyConstraint('name', new Assert\NotBlank());
-            $metadata->addPropertyConstraint('name', new Assert\Length([
-                'min' => 5,
-                'max' => 20,
-            ]));
+            $metadata->addPropertyConstraint('name', new Assert\Length(
+                min: 5,
+                max: 20,
+            ));
         }
     }
 
@@ -83,70 +83,9 @@ configure the locations of these files::
     :method:`Symfony\\Component\\Validator\\ValidatorBuilder::addXmlMappings`
     to configure an array of file paths.
 
-The AnnotationLoader
---------------------
-
-.. deprecated:: 6.4
-
-    The :class:`Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader`
-    is deprecated since Symfony 6.4, use the
-    :class:`Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader`
-    instead.
-
-The component provides an
-:class:`Symfony\\Component\\Validator\\Mapping\\Loader\\AnnotationLoader` to get
-the metadata from the annotations of the class. Annotations are defined as ``@``
-prefixed classes included in doc block comments (``/** ... */``). For example::
-
-    use Symfony\Component\Validator\Constraints as Assert;
-    // ...
-
-    class User
-    {
-        /**
-         * @Assert\NotBlank
-         */
-        protected string $name;
-    }
-
-To enable the annotation loader, call the
-:method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping` method.
-If you use annotations instead of attributes, it's also required to call
-``addDefaultDoctrineAnnotationReader()`` to use Doctrine's annotation reader::
-
-    use Symfony\Component\Validator\Validation;
-
-    $validator = Validation::createValidatorBuilder()
-        ->enableAnnotationMapping()
-        ->addDefaultDoctrineAnnotationReader() // add this only when using annotations
-        ->getValidator();
-
-.. deprecated:: 6.4
-
-    Annotations are deprecated since Symfony 6.4, use attributes instead.
-
-To disable the annotation loader after it was enabled, call
-:method:`Symfony\\Component\\Validator\\ValidatorBuilder::disableAnnotationMapping`.
-
-.. deprecated:: 6.4
-
-    The :method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAnnotationMapping`
-    and :method:`Symfony\\Component\\Validator\\ValidatorBuilder::disableAnnotationMapping`
-    methods are deprecated since Symfony 6.4, use the
-    :method:`Symfony\\Component\\Validator\\ValidatorBuilder::enableAttributeMapping`
-    and :method:`Symfony\\Component\\Validator\\ValidatorBuilder::disableAttributeMapping`
-    methods instead.
-
-.. include:: /_includes/_annotation_loader_tip.rst.inc
-
 The AttributeLoader
 -------------------
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader`
-    was introduced in Symfony 6.4.
-
 The component provides an
 :class:`Symfony\\Component\\Validator\\Mapping\\Loader\\AttributeLoader` to get
 the metadata from the attributes of the class. For example::
diff --git a/components/var_dumper.rst b/components/var_dumper.rst
index cfc57140b52..c6966a692af 100644
--- a/components/var_dumper.rst
+++ b/components/var_dumper.rst
@@ -485,10 +485,6 @@ then its dump representation::
 .. image:: /_images/components/var_dumper/10-uninitialized.png
     :alt: Dump output where the uninitialized property is represented by a question mark followed by the type definition.
 
-.. versionadded:: 6.4
-
-    Displaying uninitialized variables information was introduced in Symfony 6.4.
-
 .. _var-dumper-advanced:
 
 Advanced Usage
diff --git a/components/var_exporter.rst b/components/var_exporter.rst
index cb935c22da4..c7ec9cd90d0 100644
--- a/components/var_exporter.rst
+++ b/components/var_exporter.rst
@@ -177,25 +177,53 @@ populated by using the special ``"\0"`` property name to define their internal v
         "\0" => [$inputArray],
     ]);
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Component\\VarExporter\\Hydrator` was introduced in Symfony 6.2.
-
 Creating Lazy Objects
 ---------------------
 
-Lazy-objects are objects instantiated empty and populated on-demand. This is
-particularly useful when you have for example properties in your classes that
-requires some heavy computation to determine their value. In this case, you
-may want to trigger the property's value processing only when you actually need
-its value. Thanks to this, the heavy computation won't be done if you never use
-this property. The VarExporter component is bundled with two traits helping
-you implement such mechanism easily in your classes.
+Lazy objects are objects instantiated empty and populated on demand. This is
+particularly useful when, for example, a class has properties that require
+heavy computation to determine their values. In such cases, you may want to
+trigger the computation only when the property is actually accessed. This way,
+the expensive processing is avoided entirely if the property is never used.
+
+Since version 8.4, PHP provides support for lazy objects via the reflection API.
+This native API works with concrete classes, but not with abstract or internal ones.
+This component provides helpers to generate lazy objects using the decorator
+pattern, which also works with abstract classes, internal classes, and interfaces::
+
+    $proxyCode = ProxyHelper::generateLazyProxy(new \ReflectionClass(SomeInterface::class));
+    // $proxyCode should be dumped into a file in production environments
+    eval('class ProxyDecorator'.$proxyCode);
+
+    $proxy = ProxyDecorator::createLazyProxy(initializer: function (): SomeInterface {
+        // use whatever heavy logic you need here
+        // to compute the $dependencies of the proxied class
+        $instance = new SomeHeavyClass(...$dependencies);
+        // call setters, etc. if needed
+
+        return $instance;
+    });
+
+Use this mechanism only when native lazy objects cannot be leveraged
+(otherwise you'll get a deprecation notice).
+
+Legacy Creation of Lazy Objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using a PHP version earlier than 8.4, native lazy objects are not available.
+In these cases, the VarExporter component provides two traits that help you
+implement lazy-loading mechanisms in your classes.
 
 .. _var-exporter_ghost-objects:
 
 LazyGhostTrait
-~~~~~~~~~~~~~~
+..............
+
+.. deprecated:: 7.3
+
+    ``LazyGhostTrait`` is deprecated since Symfony 7.3. Use PHP 8.4's native lazy
+    objects instead. Note that using the trait with PHP versions earlier than 8.4
+    does not trigger a deprecation, to ease the transition.
 
 Ghost objects are empty objects, which see their properties populated the first
 time any method is called. Thanks to :class:`Symfony\\Component\\VarExporter\\LazyGhostTrait`,
@@ -225,12 +253,6 @@ initialized::
         }
     }
 
-.. deprecated:: 6.4
-
-    Using an array of closures for property-based initialization in the
-    ``createLazyGhost()`` method is deprecated since Symfony 6.4. Pass
-    a single closure that initializes the whole object instead.
-
 :class:`Symfony\\Component\\VarExporter\\LazyGhostTrait` also allows to
 convert non-lazy classes to lazy ones::
 
@@ -274,35 +296,20 @@ While you never query ``$processor->hash`` value, heavy methods will never be
 triggered. But still, the ``$processor`` object exists and can be used in your
 code, passed to methods, functions, etc.
 
-Additionally and by adding two arguments to the initializer function, it is
-possible to initialize properties one-by-one::
-
-    $processor = LazyHashProcessor::createLazyGhost(initializer: function (HashProcessor $instance, string $propertyName, ?string $propertyScope): mixed {
-        if (HashProcessor::class === $propertyScope && 'hash' === $propertyName) {
-            // Return $hash value
-        }
-
-        // Then you can add more logic for the other properties
-    });
-
-.. deprecated:: 6.4
-
-   The use of ``propertyName`` and ``propertyScope`` in the initializer function
-   is deprecated since Symfony 6.4 and will be removed in Symfony 7.0.
-   The initializer should now handle the entire object initialization at once.
-
 Ghost objects unfortunately can't work with abstract classes or internal PHP
 classes. Nevertheless, the VarExporter component covers this need with the help
 of :ref:`Virtual Proxies <var-exporter_virtual-proxies>`.
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Component\\VarExporter\\LazyGhostTrait` was introduced in Symfony 6.2.
-
 .. _var-exporter_virtual-proxies:
 
 LazyProxyTrait
-~~~~~~~~~~~~~~
+..............
+
+.. deprecated:: 7.3
+
+    ``LazyProxyTrait`` is deprecated since Symfony 7.3. Use PHP 8.4's native lazy
+    objects instead. Note that using the trait with PHP versions earlier than 8.4
+    does not trigger a deprecation, to ease the transition.
 
 The purpose of virtual proxies in the same one as
 :ref:`ghost objects <var-exporter_ghost-objects>`, but their internal behavior is
@@ -364,10 +371,5 @@ Just like ghost objects, while you never query ``$processor->hash``, its value
 will not be computed. The main difference with ghost objects is that this time,
 a proxy of an abstract class was created. This also works with internal PHP class.
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Component\\VarExporter\\LazyProxyTrait` and
-    :class:`Symfony\\Component\\VarExporter\\ProxyHelper` were introduced in Symfony 6.2.
-
 .. _`OPcache`: https://www.php.net/opcache
 .. _`PSR-2`: https://www.php-fig.org/psr/psr-2/
diff --git a/components/yaml.rst b/components/yaml.rst
index 700ebd22379..efaf84f04e6 100644
--- a/components/yaml.rst
+++ b/components/yaml.rst
@@ -214,6 +214,8 @@ During the parsing of the YAML contents, all the ``_`` characters are removed
 from the numeric literal contents, so there is not a limit in the number of
 underscores you can include or the way you group contents.
 
+.. _yaml-flags:
+
 Advanced Usage: Flags
 ---------------------
 
@@ -355,9 +357,25 @@ and the special ``!php/enum`` syntax to parse them as proper PHP enums::
     // the value of the 'foo' key is a string because it missed the `!php/enum` syntax
     // $parameters = ['foo' => 'FooEnum::Foo', 'bar' => 'foo'];
 
-.. versionadded:: 6.2
+You can also use ``!php/enum`` to get all the enumeration cases by only
+giving the enumeration FQCN::
 
-    The support for PHP enumerations was introduced in Symfony 6.2.
+    enum FooEnum: string
+    {
+        case Foo = 'foo';
+        case Bar = 'bar';
+    }
+
+    // ...
+
+    $yaml = '{ bar: !php/enum FooEnum }';
+    $parameters = Yaml::parse($yaml, Yaml::PARSE_CONSTANT);
+    // $parameters = ['bar' => ['foo', 'bar']];
+
+.. versionadded:: 7.1
+
+    The support for using the enum FQCN without specifying a case
+    was introduced in Symfony 7.1.
 
 Parsing and Dumping of Binary Data
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -410,6 +428,16 @@ you can dump them as ``~`` with the ``DUMP_NULL_AS_TILDE`` flag::
     $dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_TILDE);
     // foo: ~
 
+Another valid representation of the ``null`` value is an empty string. You can
+use the ``DUMP_NULL_AS_EMPTY`` flag to dump null values as empty strings::
+
+    $dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_EMPTY);
+    // foo:
+
+.. versionadded:: 7.3
+
+    The ``DUMP_NULL_AS_EMPTY`` flag was introduced in Symfony 7.3.
+
 Dumping Numeric Keys as Strings
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -422,9 +450,57 @@ By default, digit-only array keys are dumped as integers. You can use the
     $dumped = Yaml::dump([200 => 'foo'], 2, 4, Yaml::DUMP_NUMERIC_KEY_AS_STRING);
     // '200': foo
 
-.. versionadded:: 6.3
+Dumping Double Quotes on Values
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, only unsafe string values are enclosed in double quotes (for example,
+if they are reserved words or contain newlines and spaces). Use the
+``DUMP_FORCE_DOUBLE_QUOTES_ON_VALUES`` flag to add double quotes to all string values::
+
+    $dumped = Yaml::dump([
+        'foo' => 'bar', 'some foo' => 'some bar', 'x' => 3.14, 'y' => true, 'z' => null,
+    ]);
+    // foo: bar, 'some foo': 'some bar', x: 3.14, 'y': true, z: null
+
+    $dumped = Yaml::dump([
+        'foo' => 'bar', 'some foo' => 'some bar', 'x' => 3.14, 'y' => true, 'z' => null,
+    ], 2, 4, Yaml::DUMP_FORCE_DOUBLE_QUOTES_ON_VALUES);
+    // "foo": "bar", "some foo": "some bar", "x": 3.14, "y": true, "z": null
+
+.. versionadded:: 7.3
+
+    The ``Yaml::DUMP_FORCE_DOUBLE_QUOTES_ON_VALUES`` flag was introduced in Symfony 7.3.
+
+Dumping Collection of Maps
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the YAML component dumps collections of maps, it uses a hyphen on a separate
+line as a delimiter:
+
+.. code-block:: yaml
+
+    planets:
+      -
+        name: Mercury
+        distance: 57910000
+      -
+        name: Jupiter
+        distance: 778500000
+
+To produce a more compact output where the delimiter is included within the map,
+use the ``Yaml::DUMP_COMPACT_NESTED_MAPPING`` flag:
+
+.. code-block:: yaml
+
+    planets:
+      - name: Mercury
+        distance: 57910000
+      - name: Jupiter
+        distance: 778500000
+
+.. versionadded:: 7.3
 
-    The ``DUMP_NUMERIC_KEY_AS_STRING`` flag was introduced in Symfony 6.3.
+    The ``Yaml::DUMP_COMPACT_NESTED_MAPPING`` flag was introduced in Symfony 7.3.
 
 Syntax Validation
 ~~~~~~~~~~~~~~~~~
diff --git a/configuration.rst b/configuration.rst
index 625e93b12d0..4b1e75dcabe 100644
--- a/configuration.rst
+++ b/configuration.rst
@@ -81,10 +81,6 @@ readable. These are the main advantages and disadvantages of each format:
     methods in the ``src/Kernel.php`` file to add support for the ``.xml`` file
     extension.
 
-    .. versionadded:: 6.1
-
-        The automatic loading of PHP configuration files was introduced in Symfony 6.1.
-
 Importing Configuration Files
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -292,14 +288,6 @@ reusable configuration value. By convention, parameters are defined under the
             something@example.com
         </parameter>
 
-.. versionadded:: 6.2
-
-    Passing an enum case as a service parameter was introduced in Symfony 6.2.
-
-.. versionadded:: 6.3
-
-    The ``trim`` attribute was introduced in Symfony 6.3.
-
 Once defined, you can reference this parameter value from any other
 configuration file using a special syntax: wrap the parameter name in two ``%``
 (e.g. ``%app.admin_email%``):
@@ -394,9 +382,19 @@ a new ``locale`` parameter is added to the ``config/services.yaml`` file).
     They are useful when working with :doc:`Compiler Passes </service_container/compiler_passes>`
     to declare some temporary parameters that won't be available later in the application.
 
-.. versionadded:: 6.3
+Configuration parameters are usually validation-free, but you can ensure that
+essential parameters for your application's functionality are not empty::
+
+    /** @var ContainerBuilder $container */
+    $container->parameterCannotBeEmpty('app.private_key', 'Did you forget to set a value for the "app.private_key" parameter?');
 
-    Compile-time parameters were introduced in Symfony 6.3.
+If a non-empty parameter is ``null``, an empty string ``''``, or an empty array ``[]``,
+Symfony will throw an exception. This validation is **not** made at compile time
+but when attempting to retrieve the value of the parameter.
+
+.. versionadded:: 7.2
+
+    Validating non-empty parameters was introduced in Symfony 7.2.
 
 .. seealso::
 
@@ -948,6 +946,49 @@ get the environment variables and will not spend time parsing the ``.env`` files
     Update your deployment tools/workflow to run the ``dotenv:dump`` command after
     each deploy to improve the application performance.
 
+Storing Environment Variables In Other Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, the environment variables are stored in the ``.env`` file located
+at the root of your project. However, you can store them in other files in
+multiple ways.
+
+If you use the :doc:`Runtime component </components/runtime>`, the dotenv
+path is part of the options you can set in your ``composer.json`` file:
+
+.. code-block:: json
+
+      {
+          // ...
+          "extra": {
+              // ...
+              "runtime": {
+                  "dotenv_path": "my/custom/path/to/.env"
+              }
+          }
+      }
+
+As an alternate option, you can directly invoke the ``Dotenv`` class in your
+``bootstrap.php`` file or any other file of your application::
+
+    use Symfony\Component\Dotenv\Dotenv;
+
+    (new Dotenv())->bootEnv(dirname(__DIR__).'my/custom/path/to/.env');
+
+Symfony will then look for the environment variables in that file, but also in
+the local and environment-specific files (e.g. ``.*.local`` and
+``.*.<environment>.local``). Read
+:ref:`how to override environment variables <configuration-multiple-env-files>`
+to learn more about this.
+
+If you need to know the path to the ``.env`` file that Symfony is using, you can
+read the ``SYMFONY_DOTENV_PATH`` environment variable in your application.
+
+.. versionadded:: 7.1
+
+    The ``SYMFONY_DOTENV_PATH`` environment variable was introduced in Symfony
+    7.1.
+
 .. _configuration-secrets:
 
 Encrypting Environment Variables (Secrets)
@@ -992,10 +1033,6 @@ Use the ``debug:dotenv`` command to understand how Symfony parses the different
     # look for a specific variable passing its full or partial name as an argument
     $ php bin/console debug:dotenv foo
 
-.. versionadded:: 6.2
-
-    The option to pass variable names to ``debug:dotenv`` was introduced in Symfony 6.2.
-
 Additionally, and regardless of how you set environment variables, you can see all
 environment variables, with their values, referenced in Symfony's container configuration,
 you can also see the number of occurrences of each environment variable in the container:
diff --git a/configuration/env_var_processors.rst b/configuration/env_var_processors.rst
index ecf5d37cc05..936d93c1061 100644
--- a/configuration/env_var_processors.rst
+++ b/configuration/env_var_processors.rst
@@ -419,10 +419,6 @@ Symfony provides the following env var processors:
                     ->set(\RedisCluster::class, \RedisCluster::class)->args([null, '%env(shuffle:csv:REDIS_NODES)%']);
             };
 
-    .. versionadded:: 6.2
-
-        The ``env(shuffle:...)`` env var processor was introduced in Symfony 6.2.
-
 ``env(file:FOO)``
     Returns the contents of a file whose path is the value of the ``FOO`` env var:
 
@@ -788,10 +784,6 @@ Symfony provides the following env var processors:
     The value stored in the ``CARD_SUIT`` env var would be a string (e.g. ``'spades'``)
     but the application will use the enum value (e.g. ``Suit::Spades``).
 
-    .. versionadded:: 6.2
-
-        The ``env(enum:...)`` env var processor was introduced in Symfony 6.2.
-
 ``env(defined:NO_FOO)``
     Evaluates to ``true`` if the env var exists and its value is not ``''``
     (an empty string) or ``null``; it returns ``false`` otherwise.
@@ -826,9 +818,56 @@ Symfony provides the following env var processors:
             // config/services.php
             $container->setParameter('typed_env', '%env(defined:FOO)%');
 
-    .. versionadded:: 6.4
+.. _urlencode_environment_variable_processor:
+
+``env(urlencode:FOO)``
+    Encodes the content of the ``FOO`` env var using the :phpfunction:`urlencode`
+    PHP function. This is especially useful when ``FOO`` value is not compatible
+    with DSN syntax.
+
+    .. configuration-block::
+
+        .. code-block:: yaml
+
+            # config/packages/framework.yaml
+            parameters:
+                env(DATABASE_URL): 'mysql://db_user:foo@b$r@127.0.0.1:3306/db_name'
+                encoded_database_url: '%env(urlencode:DATABASE_URL)%'
+
+        .. code-block:: xml
+
+            <!-- config/packages/framework.xml -->
+            <?xml version="1.0" encoding="UTF-8" ?>
+            <container xmlns="http://symfony.com/schema/dic/services"
+                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                xmlns:framework="http://symfony.com/schema/dic/symfony"
+                xsi:schemaLocation="http://symfony.com/schema/dic/services
+                    https://symfony.com/schema/dic/services/services-1.0.xsd
+                    http://symfony.com/schema/dic/symfony
+                    https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+                <parameters>
+                    <parameter key="env(DATABASE_URL)">mysql://db_user:foo@b$r@127.0.0.1:3306/db_name</parameter>
+                    <parameter key="encoded_database_url">%env(urlencode:DATABASE_URL)%</parameter>
+                </parameters>
+            </container>
+
+        .. code-block:: php
+
+            // config/packages/framework.php
+            namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+            use Symfony\Component\DependencyInjection\ContainerBuilder;
+            use Symfony\Config\FrameworkConfig;
+
+            return static function (ContainerBuilder $container): void {
+                $container->setParameter('env(DATABASE_URL)', 'mysql://db_user:foo@b$r@127.0.0.1:3306/db_name');
+                $container->setParameter('encoded_database_url', '%env(urlencode:DATABASE_URL)%');
+            };
+
+    .. versionadded:: 7.1
 
-        The ``env(defined:...)`` env var processor was introduced in Symfony 6.4.
+        The ``env(urlencode:...)`` env var processor was introduced in Symfony 7.1.
 
 It is also possible to combine any number of processors:
 
diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst
index 511a15a69fd..542532ee1af 100644
--- a/configuration/micro_kernel_trait.rst
+++ b/configuration/micro_kernel_trait.rst
@@ -16,9 +16,7 @@ via Composer:
 
 .. code-block:: terminal
 
-    $ composer require symfony/config symfony/http-kernel \
-      symfony/http-foundation symfony/routing \
-      symfony/dependency-injection symfony/framework-bundle
+    $ composer require symfony/framework-bundle symfony/runtime
 
 Next, create an ``index.php`` file that defines the kernel class and runs it:
 
@@ -34,19 +32,12 @@ Next, create an ``index.php`` file that defines the kernel class and runs it:
         use Symfony\Component\HttpKernel\Kernel as BaseKernel;
         use Symfony\Component\Routing\Attribute\Route;
 
-        require __DIR__.'/vendor/autoload.php';
+        require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
 
         class Kernel extends BaseKernel
         {
             use MicroKernelTrait;
 
-            public function registerBundles(): array
-            {
-                return [
-                    new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
-                ];
-            }
-
             protected function configureContainer(ContainerConfigurator $container): void
             {
                 // PHP equivalent of config/packages/framework.yaml
@@ -64,11 +55,9 @@ Next, create an ``index.php`` file that defines the kernel class and runs it:
             }
         }
 
-        $kernel = new Kernel('dev', true);
-        $request = Request::createFromGlobals();
-        $response = $kernel->handle($request);
-        $response->send();
-        $kernel->terminate($request, $response);
+        return static function (array $context) {
+            return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
+        };
 
     .. code-block:: php
 
@@ -80,19 +69,12 @@ Next, create an ``index.php`` file that defines the kernel class and runs it:
         use Symfony\Component\HttpKernel\Kernel as BaseKernel;
         use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
 
-        require __DIR__.'/vendor/autoload.php';
+        require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
 
         class Kernel extends BaseKernel
         {
             use MicroKernelTrait;
 
-            public function registerBundles(): array
-            {
-                return [
-                    new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
-                ];
-            }
-
             protected function configureContainer(ContainerConfigurator $container): void
             {
                 // PHP equivalent of config/packages/framework.yaml
@@ -114,21 +96,9 @@ Next, create an ``index.php`` file that defines the kernel class and runs it:
             }
         }
 
-        $kernel = new Kernel('dev', true);
-        $request = Request::createFromGlobals();
-        $response = $kernel->handle($request);
-        $response->send();
-        $kernel->terminate($request, $response);
-
-.. versionadded:: 6.1
-
-    The PHP attributes notation has been introduced in Symfony 6.1.
-
-.. note::
-
-    In addition to the ``index.php`` file, you'll need to create a directory called
-    ``config/`` in your project (even if it's empty because you define the configuration
-    options inside the ``configureContainer()`` method).
+        return static function (array $context) {
+            return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
+        };
 
 That's it! To test it, start the :ref:`Symfony local web server <symfony-cli-server>`:
 
@@ -138,6 +108,23 @@ That's it! To test it, start the :ref:`Symfony local web server <symfony-cli-ser
 
 Then see the JSON response in your browser: http://localhost:8000/random/10
 
+.. tip::
+
+    If your kernel only defines a single controller, you can use an invokable method::
+
+        class Kernel extends BaseKernel
+        {
+            use MicroKernelTrait;
+
+            // ...
+
+            #[Route('/random/{limit}', name: 'random_number')]
+            public function __invoke(int $limit): JsonResponse
+            {
+                // ...
+            }
+        }
+
 The Methods of a "Micro" Kernel
 -------------------------------
 
@@ -145,7 +132,26 @@ When you use the ``MicroKernelTrait``, your kernel needs to have exactly three m
 that define your bundles, your services and your routes:
 
 **registerBundles()**
-    This is the same ``registerBundles()`` that you see in a normal kernel.
+    This is the same ``registerBundles()`` that you see in a normal kernel. By
+    default, the micro kernel only registers the ``FrameworkBundle``. If you need
+    to register more bundles, override this method::
+
+        use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
+        use Symfony\Bundle\TwigBundle\TwigBundle;
+        // ...
+
+        class Kernel extends BaseKernel
+        {
+            use MicroKernelTrait;
+
+            // ...
+
+            public function registerBundles(): array
+            {
+                yield new FrameworkBundle();
+                yield new TwigBundle();
+            }
+        }
 
 **configureContainer(ContainerConfigurator $container)**
     This method builds and configures the container. In practice, you will use
@@ -154,9 +160,13 @@ that define your bundles, your services and your routes:
     services directly in PHP or load external configuration files (shown below).
 
 **configureRoutes(RoutingConfigurator $routes)**
-    Your job in this method is to add routes to the application. The
-    ``RoutingConfigurator`` has methods that make adding routes in PHP more
-    fun. You can also load external routing files (shown below).
+    In this method, you can use the ``RoutingConfigurator`` object to define routes
+    in your application and associate them to the controllers defined in this very
+    same file.
+
+    However, it's more convenient to define the controller routes using PHP attributes,
+    as shown above. That's why this method is commonly used only to load external
+    routing files (e.g. from bundles) as shown below.
 
 Adding Interfaces to "Micro" Kernel
 -----------------------------------
@@ -234,7 +244,10 @@ Now it looks like this::
     namespace App;
 
     use App\DependencyInjection\AppExtension;
+    use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
     use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
+    use Symfony\Bundle\TwigBundle\TwigBundle;
+    use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
     use Symfony\Component\DependencyInjection\ContainerBuilder;
     use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
     use Symfony\Component\HttpKernel\Kernel as BaseKernel;
@@ -244,18 +257,14 @@ Now it looks like this::
     {
         use MicroKernelTrait;
 
-        public function registerBundles(): array
+        public function registerBundles(): iterable
         {
-            $bundles = [
-                new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
-                new \Symfony\Bundle\TwigBundle\TwigBundle(),
-            ];
+            yield new FrameworkBundle();
+            yield new TwigBundle();
 
             if ('dev' === $this->getEnvironment()) {
-                $bundles[] = new \Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
+                yield new WebProfilerBundle();
             }
-
-            return $bundles;
         }
 
         protected function build(ContainerBuilder $containerBuilder): void
@@ -287,8 +296,8 @@ Now it looks like this::
         {
             // import the WebProfilerRoutes, only if the bundle is enabled
             if (isset($this->bundles['WebProfilerBundle'])) {
-                $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.xml')->prefix('/_wdt');
-                $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.xml')->prefix('/_profiler');
+                $routes->import('@WebProfilerBundle/Resources/config/routing/wdt.php', 'php')->prefix('/_wdt');
+                $routes->import('@WebProfilerBundle/Resources/config/routing/profiler.php', 'php')->prefix('/_profiler');
             }
 
             // load the routes defined as PHP attributes
@@ -296,19 +305,16 @@ Now it looks like this::
             $routes->import(__DIR__.'/Controller/', 'attribute');
         }
 
-        // optional, to use the standard Symfony cache directory
-        public function getCacheDir(): string
-        {
-            return __DIR__.'/../var/cache/'.$this->getEnvironment();
-        }
-
-        // optional, to use the standard Symfony logs directory
-        public function getLogDir(): string
-        {
-            return __DIR__.'/../var/log';
-        }
+        // optionally, you can define the getCacheDir() and getLogDir() methods
+        // to override the default locations for these directories
     }
 
+
+.. versionadded:: 7.3
+
+    The ``wdt.php`` and ``profiler.php`` files were introduced in Symfony 7.3.
+    Previously, you had to import ``wdt.xml`` and ``profiler.xml``
+
 Before continuing, run this command to add support for the new dependencies:
 
 .. code-block:: terminal
@@ -344,10 +350,6 @@ add a service conditionally based on the ``foo`` value::
         }
     }
 
-.. versionadded:: 6.1
-
-    The ``AbstractExtension`` class was introduced in Symfony 6.1.
-
 Unlike the previous kernel, this loads an external ``config/framework.yaml`` file,
 because the configuration started to get bigger:
 
diff --git a/configuration/multiple_kernels.rst b/configuration/multiple_kernels.rst
index dd857fff243..ec8742213b5 100644
--- a/configuration/multiple_kernels.rst
+++ b/configuration/multiple_kernels.rst
@@ -117,7 +117,9 @@ resources::
     // src/Kernel.php
     namespace Shared;
 
+    use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
     use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+    use Symfony\Component\HttpKernel\Kernel as BaseKernel;
     use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
 
     class Kernel extends BaseKernel
@@ -258,6 +260,7 @@ the application ID to run under CLI context::
 
     // bin/console
     use Shared\Kernel;
+    use Symfony\Bundle\FrameworkBundle\Console\Application;
     use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Input\InputOption;
 
diff --git a/configuration/secrets.rst b/configuration/secrets.rst
index 653bd92f611..285b89d521e 100644
--- a/configuration/secrets.rst
+++ b/configuration/secrets.rst
@@ -166,6 +166,22 @@ secrets' values by passing the ``--reveal`` option:
       DATABASE_PASSWORD   "my secret"
      ------------------- ------------ -------------
 
+Reveal Existing Secrets
+-----------------------
+
+If you have the **decryption key**, the ``secrets:reveal`` command allows
+you to reveal a single secret's value.
+
+.. code-block:: terminal
+
+    $ php bin/console secrets:reveal DATABASE_PASSWORD
+
+     my secret
+
+.. versionadded:: 7.1
+
+    The ``secrets:reveal`` command was introduced in Symfony 7.1.
+
 Remove Secrets
 --------------
 
@@ -295,7 +311,7 @@ The secrets system is enabled by default and some of its behavior can be configu
                 xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
                     http://symfony.com/schema/dic/framework https://symfony.com/schema/dic/framework/framework-1.0.xsd"
             >
-                <framework:config secret="%env(APP_SECRET)%">
+                <framework:config>
                     <framework:secrets
                         vault_directory="%kernel.project_dir%/config/secrets/%kernel.environment%"
                         local_dotenv_file="%kernel.project_dir%/.env.%kernel.environment%.local"
diff --git a/console.rst b/console.rst
index 24439f6a45c..be9292f92a5 100644
--- a/console.rst
+++ b/console.rst
@@ -67,14 +67,6 @@ command, for instance:
 Console Completion
 ~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.1
-
-    Console completion for Fish was introduced in Symfony 6.1.
-
-.. versionadded:: 6.2
-
-    Console completion for Zsh was introduced in Symfony 6.2.
-
 If you are using the Bash, Zsh or Fish shell, you can install Symfony's
 completion script to get auto completion when typing commands in the
 terminal. All commands support name and option completion, and some can
@@ -111,26 +103,25 @@ completion (by default, by pressing the Tab key).
     If you are using the :doc:`Symfony CLI </setup/symfony_cli>` tool, follow
     :ref:`these instructions <symfony-cli-autocompletion>` to enable autocompletion.
 
+.. _console_creating-command:
+
 Creating a Command
 ------------------
 
-Commands are defined in classes extending
-:class:`Symfony\\Component\\Console\\Command\\Command`. For example, you may
-want a command to create a user::
+Commands are defined in classes and auto-registered using the ``#[AsCommand]``
+attribute. For example, you may want a command to create a user::
 
     // src/Command/CreateUserCommand.php
     namespace App\Command;
 
     use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
 
     // the name of the command is what users type after "php bin/console"
     #[AsCommand(name: 'app:create-user')]
-    class CreateUserCommand extends Command
+    class CreateUserCommand
     {
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(): int
         {
             // ... put here the code to create the user
 
@@ -151,117 +142,54 @@ want a command to create a user::
         }
     }
 
-Configuring the Command
-~~~~~~~~~~~~~~~~~~~~~~~
-
-You can optionally define a description, help message and the
-:doc:`input options and arguments </console/input>` by overriding the
-``configure()`` method::
+If you can't use PHP attributes, register the command as a service and
+:doc:`tag it </service_container/tags>` with the ``console.command`` tag. If you're using the
+:ref:`default services.yaml configuration <service-container-services-load-example>`,
+this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`.
 
-    // src/Command/CreateUserCommand.php
+You can also use ``#[AsCommand]`` to add a description and longer help text for the command::
 
-    // ...
-    class CreateUserCommand extends Command
+    #[AsCommand(
+        name: 'app:create-user',
+        description: 'Creates a new user.', // the command description shown when running "php bin/console list"
+        help: 'This command allows you to create a user...', // the command help shown when running the command with the "--help" option
+    )]
+    class CreateUserCommand
     {
-        // the command description shown when running "php bin/console list"
-        protected static $defaultDescription = 'Creates a new user.';
-
-        // ...
-        protected function configure(): void
+        public function __invoke(): int
         {
-            $this
-                // the command help shown when running the command with the "--help" option
-                ->setHelp('This command allows you to create a user...')
-            ;
+            // ...
         }
     }
 
-.. tip::
-
-    Defining the ``$defaultDescription`` static property instead of using the
-    ``setDescription()`` method allows to get the command description without
-    instantiating its class. This makes the ``php bin/console list`` command run
-    much faster.
-
-    If you want to always run the ``list`` command fast, add the ``--short`` option
-    to it (``php bin/console list --short``). This will avoid instantiating command
-    classes, but it won't show any description for commands that use the
-    ``setDescription()`` method instead of the static property.
-
-.. deprecated:: 6.1
+Additionally, you can extend the :class:`Symfony\\Component\\Console\\Command\\Command` class to
+leverage advanced features like lifecycle hooks (e.g. :method:`Symfony\\Component\\Console\\Command\\Command::initialize` and
+and :method:`Symfony\\Component\\Console\\Command\\Command::interact`)::
 
-    The static property ``$defaultDescription`` was deprecated in Symfony 6.1.
-    Instead, use the ``#[AsCommand]`` attribute to define the optional command
-    description.
-
-The ``configure()`` method is called automatically at the end of the command
-constructor. If your command defines its own constructor, set the properties
-first and then call to the parent constructor, to make those properties
-available in the ``configure()`` method::
-
-    // ...
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputArgument;
+    use Symfony\Component\Console\Input\InputInterface;
+    use Symfony\Component\Console\Output\OutputInterface;
 
+    #[AsCommand(name: 'app:create-user')]
     class CreateUserCommand extends Command
     {
-        // ...
-
-        public function __construct(bool $requirePassword = false)
+        public function initialize(InputInterface $input, OutputInterface $output): void
         {
-            // best practices recommend to call the parent constructor first and
-            // then set your own properties. That wouldn't work in this case
-            // because configure() needs the properties set in this constructor
-            $this->requirePassword = $requirePassword;
-
-            parent::__construct();
+            // ...
         }
 
-        protected function configure(): void
+        public function interact(InputInterface $input, OutputInterface $output): void
         {
-            $this
-                // ...
-                ->addArgument('password', $this->requirePassword ? InputArgument::REQUIRED : InputArgument::OPTIONAL, 'User password')
-            ;
+            // ...
         }
-    }
-
-.. _console_registering-the-command:
-
-Registering the Command
-~~~~~~~~~~~~~~~~~~~~~~~
 
-You can register the command by adding the ``AsCommand`` attribute to it::
-
-    // src/Command/CreateUserCommand.php
-    namespace App\Command;
-
-    use Symfony\Component\Console\Attribute\AsCommand;
-    use Symfony\Component\Console\Command\Command;
-
-    // the "name" and "description" arguments of AsCommand replace the
-    // static $defaultName and $defaultDescription properties
-    #[AsCommand(
-        name: 'app:create-user',
-        description: 'Creates a new user.',
-        hidden: false,
-        aliases: ['app:add-user']
-    )]
-    class CreateUserCommand extends Command
-    {
-        // ...
+        public function __invoke(): int
+        {
+            // ...
+        }
     }
 
-If you can't use PHP attributes, register the command as a service and
-:doc:`tag it </service_container/tags>` with the ``console.command`` tag. If you're using the
-:ref:`default services.yaml configuration <service-container-services-load-example>`,
-this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`.
-
-.. deprecated:: 6.1
-
-    The static property ``$defaultName`` was deprecated in Symfony 6.1.
-    Define your command name with the ``#[AsCommand]`` attribute instead.
-
 Running the Command
 ~~~~~~~~~~~~~~~~~~~
 
@@ -272,16 +200,16 @@ After configuring and registering the command, you can run it in the terminal:
     $ php bin/console app:create-user
 
 As you might expect, this command will do nothing as you didn't write any logic
-yet. Add your own logic inside the ``execute()`` method.
+yet. Add your own logic inside the ``__invoke()`` method.
 
 Console Output
 --------------
 
-The ``execute()`` method has access to the output stream to write messages to
+The ``__invoke()`` method has access to the output stream to write messages to
 the console::
 
     // ...
-    protected function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(OutputInterface $output): int
     {
         // outputs multiple lines to the console (adding "\n" at the end of each line)
         $output->writeln([
@@ -332,9 +260,10 @@ method, which returns an instance of
     // ...
     use Symfony\Component\Console\Output\ConsoleOutputInterface;
 
-    class MyCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output): int
         {
             if (!$output instanceof ConsoleOutputInterface) {
                 throw new \LogicException('This command accepts only an instance of "ConsoleOutputInterface".');
@@ -378,10 +307,6 @@ method, which returns an instance of
 
     A new line is appended automatically when displaying information in a section.
 
-.. versionadded:: 6.2
-
-    The feature to limit the height of a console section was introduced in Symfony 6.2.
-
 Output sections let you manipulate the Console output in advanced ways, such as
 :ref:`displaying multiple progress bars <console-multiple-progress-bars>` which
 are updated independently and :ref:`appending rows to tables <console-modify-rendered-tables>`
@@ -397,20 +322,12 @@ Console Input
 
 Use input options or arguments to pass information to the command::
 
-    use Symfony\Component\Console\Input\InputArgument;
-
-    // ...
-    protected function configure(): void
-    {
-        $this
-            // configure an argument
-            ->addArgument('username', InputArgument::REQUIRED, 'The username of the user.')
-            // ...
-        ;
-    }
+    use Symfony\Component\Console\Attribute\Argument;
 
-    // ...
-    public function execute(InputInterface $input, OutputInterface $output): int
+    // The #[Argument] attribute configures $username as a
+    // required input argument and its value is automatically
+    // passed to this parameter
+    public function __invoke(#[Argument('The username of the user.')] string $username, OutputInterface $output): int
     {
         $output->writeln([
             'User Creator',
@@ -418,8 +335,7 @@ Use input options or arguments to pass information to the command::
             '',
         ]);
 
-        // retrieve the argument value using getArgument()
-        $output->writeln('Username: '.$input->getArgument('username'));
+        $output->writeln('Username: '.$username);
 
         return Command::SUCCESS;
     }
@@ -449,23 +365,22 @@ as a service, you can use normal dependency injection. Imagine you have a
 
     // ...
     use App\Service\UserManager;
-    use Symfony\Component\Console\Command\Command;
+    use Symfony\Component\Console\Attribute\Argument;
+    use Symfony\Component\Console\Attribute\AsCommand;
 
-    class CreateUserCommand extends Command
+    #[AsCommand(name: 'app:create-user')]
+    class CreateUserCommand
     {
         public function __construct(
-            private UserManager $userManager,
-        ){
-            parent::__construct();
+            private UserManager $userManager
+        ) {
         }
 
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(#[Argument] string $username, OutputInterface $output): int
         {
             // ...
 
-            $this->userManager->create($input->getArgument('username'));
+            $this->userManager->create($username);
 
             $output->writeln('User successfully generated!');
 
@@ -493,7 +408,7 @@ command:
     Note that it will not be called when the command is run without interaction
     (e.g. when passing the ``--no-interaction`` global option flag).
 
-:method:`Symfony\\Component\\Console\\Command\\Command::execute` *(required)*
+``__invoke()`` (or :method:`Symfony\\Component\\Console\\Command\\Command::execute`) *(required)*
     This method is executed after ``interact()`` and ``initialize()``.
     It contains the logic you want the command to execute and it must
     return an integer which will be used as the command `exit status`_.
@@ -603,11 +518,6 @@ even the color mode being used. You have access to such information thanks to th
     // changes the color mode
     $colorMode = $terminal->setColorMode(AnsiColorMode::Ansi24);
 
-.. versionadded:: 6.2
-
-    The support for setting and getting the current color mode was introduced
-    in Symfony 6.2.
-
 Logging Command Errors
 ----------------------
 
@@ -652,10 +562,6 @@ profile is accessible through the web page of the profiler.
     profile. Moreover, consider using the ``--limit`` option to only process a few
     messages to make the profile more readable in the profiler.
 
-.. versionadded:: 6.4
-
-    The ``--profile`` option was introduced in Symfony 6.4.
-
 Learn More
 ----------
 
diff --git a/console/calling_commands.rst b/console/calling_commands.rst
index dd1f0b12ff9..875ead15d2d 100644
--- a/console/calling_commands.rst
+++ b/console/calling_commands.rst
@@ -14,20 +14,18 @@ arguments and options you want to pass to the command. The command name must be
 the first argument.
 
 Eventually, calling the ``doRun()`` method actually runs the command and returns
-the returned code from the command (return value from command ``execute()``
+the returned code from the command (return value from command ``__invoke()``
 method)::
 
     // ...
-    use Symfony\Component\Console\Command;
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Input\ArrayInput;
-    use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
 
-    class CreateUserCommand extends Command
+    #[AsCommand(name: 'app:create-user')]
+    class CreateUserCommand
     {
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output): int
         {
             $greetInput = new ArrayInput([
                 // the command name is passed as first argument
diff --git a/console/coloring.rst b/console/coloring.rst
index c54045250a8..8b6655d6b71 100644
--- a/console/coloring.rst
+++ b/console/coloring.rst
@@ -58,10 +58,6 @@ Any hex color is supported for foreground and background colors. Besides that, t
     the nearest color depending on the terminal capabilities. E.g. ``#c0392b`` is
     degraded to ``#d75f5f`` in 256-color terminals and to ``red`` in 8-color terminals.
 
-    .. versionadded:: 6.2
-
-        The support for 256-color terminals was introduced in Symfony 6.2.
-
 And available options are: ``bold``, ``underscore``, ``blink``, ``reverse``
 (enables the "reverse video" mode where the background and foreground colors
 are swapped) and ``conceal`` (sets the foreground color to transparent, making
diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst
index 1393879a1df..ed5b99f9cb4 100644
--- a/console/commands_as_services.rst
+++ b/console/commands_as_services.rst
@@ -16,27 +16,16 @@ For example, suppose you want to log something from within your command::
 
     use Psr\Log\LoggerInterface;
     use Symfony\Component\Console\Attribute\AsCommand;
-    use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
 
-    #[AsCommand(name: 'app:sunshine')]
-    class SunshineCommand extends Command
+    #[AsCommand(name: 'app:sunshine', description: 'Good morning!')]
+    class SunshineCommand
     {
         public function __construct(
             private LoggerInterface $logger,
         ) {
-            // you *must* call the parent constructor
-            parent::__construct();
-        }
-
-        protected function configure(): void
-        {
-            $this
-                ->setDescription('Good morning!');
         }
 
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(): int
         {
             $this->logger->info('Waking up the sun');
             // ...
@@ -70,7 +59,7 @@ To make your command lazily loaded, either define its name using the PHP
     // ...
 
     #[AsCommand(name: 'app:sunshine')]
-    class SunshineCommand extends Command
+    class SunshineCommand
     {
         // ...
     }
diff --git a/console/hide_commands.rst b/console/hide_commands.rst
index 44a69d09289..4ab9d3a6dad 100644
--- a/console/hide_commands.rst
+++ b/console/hide_commands.rst
@@ -15,10 +15,9 @@ the ``hidden`` property of the ``AsCommand`` attribute::
     namespace App\Command;
 
     use Symfony\Component\Console\Attribute\AsCommand;
-    use Symfony\Component\Console\Command\Command;
 
     #[AsCommand(name: 'app:legacy', hidden: true)]
-    class LegacyCommand extends Command
+    class LegacyCommand
     {
         // ...
     }
diff --git a/console/input.rst b/console/input.rst
index 09cba08a41a..d5b6e4881bb 100644
--- a/console/input.rst
+++ b/console/input.rst
@@ -311,6 +311,42 @@ The above code can be simplified as follows because ``false !== null``::
     $yell = ($optionValue !== false);
     $yellLouder = ($optionValue === 'louder');
 
+Fetching The Raw Command Input
+------------------------------
+
+Symfony provides a :method:`Symfony\\Component\\Console\\Input\\ArgvInput::getRawTokens`
+method to fetch the raw input that was passed to the command. This is useful if
+you want to parse the input yourself or when you need to pass the input to another
+command without having to worry about the number of arguments or options::
+
+    // ...
+    use Symfony\Component\Process\Process;
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        // if this command was run as:
+        // php bin/console app:my-command foo --bar --baz=3 --qux=value1 --qux=value2
+
+        $tokens = $input->getRawTokens();
+        // $tokens = ['app:my-command', 'foo', '--bar', '--baz=3', '--qux=value1', '--qux=value2'];
+
+        // pass true as argument to not include the original command name
+        $tokens = $input->getRawTokens(true);
+        // $tokens = ['foo', '--bar', '--baz=3', '--qux=value1', '--qux=value2'];
+
+        // pass the raw input to any other command (from Symfony or the operating system)
+        $process = new Process(['app:other-command', ...$input->getRawTokens(true)]);
+        $process->setTty(true);
+        $process->mustRun();
+
+        // ...
+    }
+
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\Console\\Input\\ArgvInput::getRawTokens`
+    method was introduced in Symfony 7.1.
+
 Adding Argument/Option Value Completion
 ---------------------------------------
 
@@ -354,12 +390,6 @@ To achieve this, use the 5th argument of ``addArgument()`` or the 6th argument o
         }
     }
 
-.. versionadded:: 6.1
-
-    The argument to ``addOption()``/``addArgument()`` was introduced in
-    Symfony 6.1. Prior to this version, you had to override the
-    ``complete()`` method of the command.
-
 That's all you need! Assuming users "Fabien" and "Fabrice" exist, pressing
 tab after typing ``app:greet Fa`` will give you these names as a suggestion.
 
@@ -416,13 +446,18 @@ The Console component adds some predefined options to all commands:
 
 * ``--verbose``: sets the verbosity level (e.g. ``1`` the default, ``2`` and
   ``3``, or you can use respective shortcuts ``-v``, ``-vv`` and ``-vvv``)
-* ``--quiet|-q``: disables output and interaction
+* ``--silent``: disables all output and interaction, including errors
+* ``--quiet|-q``: disables output and interaction, but errors are still displayed
 * ``--no-interaction|-n``: disables interaction
 * ``--version|-V``: outputs the version number of the console application
 * ``--help|-h``: displays the command help
 * ``--ansi|--no-ansi``: whether to force of disable coloring the output
 * ``--profile``: enables the Symfony profiler
 
+.. versionadded:: 7.2
+
+    The ``--silent`` option was introduced in Symfony 7.2.
+
 When using the ``FrameworkBundle``, two more options are predefined:
 
 * ``--env|-e``: sets the Kernel configuration environment (defaults to ``APP_ENV``)
diff --git a/console/lockable_trait.rst b/console/lockable_trait.rst
index 02f635f5788..2a4fd64ffaf 100644
--- a/console/lockable_trait.rst
+++ b/console/lockable_trait.rst
@@ -13,19 +13,17 @@ that adds two convenient methods to lock and release commands::
     // ...
     use Symfony\Component\Console\Command\Command;
     use Symfony\Component\Console\Command\LockableTrait;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
+    use Symfony\Component\Console\Style\SymfonyStyle;
 
-    class UpdateContentsCommand extends Command
+    #[AsCommand(name: 'contents:update')]
+    class UpdateContentsCommand
     {
         use LockableTrait;
 
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(SymfonyStyle $io): int
         {
             if (!$this->lock()) {
-                $output->writeln('The command is already running in another process.');
+                $io->writeln('The command is already running in another process.');
 
                 return Command::SUCCESS;
             }
@@ -43,4 +41,29 @@ that adds two convenient methods to lock and release commands::
         }
     }
 
+The LockableTrait will use the ``SemaphoreStore`` if available and will default
+to ``FlockStore`` otherwise. You can override this behavior by setting
+a ``$lockFactory`` property with your own lock factory::
+
+    // ...
+    use Symfony\Component\Console\Command\Command;
+    use Symfony\Component\Console\Command\LockableTrait;
+    use Symfony\Component\Lock\LockFactory;
+
+    #[AsCommand(name: 'contents:update')]
+    class UpdateContentsCommand
+    {
+        use LockableTrait;
+
+        public function __construct(private LockFactory $lockFactory)
+        {
+        }
+
+        // ...
+    }
+
+.. versionadded::  7.1
+
+    The ``$lockFactory`` property was introduced in Symfony 7.1.
+
 .. _`locks`: https://en.wikipedia.org/wiki/Lock_(computer_science)
diff --git a/console/style.rst b/console/style.rst
index 8540ce493f2..5357b9e6172 100644
--- a/console/style.rst
+++ b/console/style.rst
@@ -7,18 +7,18 @@ questions to the user involves a lot of repetitive code.
 
 Consider for example the code used to display the title of the following command::
 
-    // src/Command/GreetCommand.php
+    // src/Command/MyCommand.php
     namespace App\Command;
 
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
     use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
 
-    class GreetCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(InputInterface $input, OutputInterface $output): int
         {
             $output->writeln([
                 '<info>Lorem Ipsum Dolor Sit Amet</>',
@@ -42,26 +42,22 @@ which allow to create *semantic* commands and forget about their styling.
 Basic Usage
 -----------
 
-In your command, instantiate the :class:`Symfony\\Component\\Console\\Style\\SymfonyStyle`
-class and pass the ``$input`` and ``$output`` variables as its arguments. Then,
-you can start using any of its helpers, such as ``title()``, which displays the
-title of the command::
+In your ``__invoke()`` method, add an argument of type :class:`Symfony\\Component\\Console\\Style\\SymfonyStyle`.
+Then, you can start using any of its helpers, such as ``title()``, which
+displays the title of the command::
 
-    // src/Command/GreetCommand.php
+    // src/Command/MyCommand.php
     namespace App\Command;
 
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
     use Symfony\Component\Console\Style\SymfonyStyle;
 
-    class GreetCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(SymfonyStyle $io): int
         {
-            $io = new SymfonyStyle($input, $output);
             $io->title('Lorem Ipsum Dolor Sit Amet');
 
             // ...
@@ -169,6 +165,32 @@ Content Methods
     styled according to the Symfony Style Guide, which allows you to use
     features such as dynamically appending rows.
 
+:method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::tree`
+    It displays the given nested array as a formatted directory/file tree
+    structure in the console output::
+
+        $io->tree([
+            'src' =>  [
+                'Controller' => [
+                    'DefaultController.php',
+                ],
+                'Kernel.php',
+            ],
+            'templates' => [
+                'base.html.twig',
+            ],
+        ]);
+
+.. versionadded:: 7.3
+
+    The ``SymfonyStyle::tree()`` and the ``SymfonyStyle::createTree()`` methods
+    were introduced in Symfony 7.3.
+
+:method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::createTree`
+    Creates an instance of :class:`Symfony\\Component\\Console\\Helper\\TreeHelper`
+    styled according to the Symfony Style Guide, which allows you to use
+    features such as dynamically nesting nodes.
+
 :method:`Symfony\\Component\\Console\\Style\\SymfonyStyle::newLine`
     It displays a blank line in the command output. Although it may seem useful,
     most of the times you won't need it at all. The reason is that every helper
@@ -339,10 +361,6 @@ User Input Methods
 
         $io->choice('Select the queue to analyze', ['queue1', 'queue2', 'queue3'], multiSelect: true);
 
-.. versionadded:: 6.2
-
-    The ``multiSelect`` option of ``choice()`` was introduced in Symfony 6.2.
-
 .. _symfony-style-blocks:
 
 Result Methods
@@ -432,29 +450,23 @@ long they are. This is done to enable clickable URLs in terminals that support t
 
 If you prefer to wrap all contents, including URLs, use this method::
 
-    // src/Command/GreetCommand.php
+    // src/Command/MyCommand.php
     namespace App\Command;
 
     // ...
     use Symfony\Component\Console\Style\SymfonyStyle;
 
-    class GreetCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(SymfonyStyle $io): int
         {
-            $io = new SymfonyStyle($input, $output);
             $io->getOutputWrapper()->setAllowCutUrls(true);
 
             // ...
         }
     }
 
-.. versionadded:: 6.2
-
-    The ``setAllowCutUrls()`` method was introduced in Symfony 6.2.
-
 Defining your Own Styles
 ------------------------
 
@@ -475,7 +487,7 @@ Then, instantiate this custom class instead of the default ``SymfonyStyle`` in
 your commands. Thanks to the ``StyleInterface`` you won't need to change the code
 of your commands to change their appearance::
 
-    // src/Command/GreetCommand.php
+    // src/Command/MyCommand.php
     namespace App\Console;
 
     use App\Console\CustomStyle;
@@ -483,16 +495,11 @@ of your commands to change their appearance::
     use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
 
-    class GreetCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        // ...
-
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(InputInterface $input, OutputInterface $output): int
         {
-            // Before
-            $io = new SymfonyStyle($input, $output);
-
-            // After
             $io = new CustomStyle($input, $output);
 
             // ...
diff --git a/console/verbosity.rst b/console/verbosity.rst
index b822e3d7534..3afd085d773 100644
--- a/console/verbosity.rst
+++ b/console/verbosity.rst
@@ -7,7 +7,10 @@ messages, but you can control their verbosity with the ``-q`` and ``-v`` options
 
 .. code-block:: terminal
 
-    # do not output any message (not even the command result messages)
+    # suppress all output, including errors
+    $ php bin/console some-command --silent
+
+    # suppress all output (even the command result messages) but display errors
     $ php bin/console some-command -q
     $ php bin/console some-command --quiet
 
@@ -23,6 +26,10 @@ messages, but you can control their verbosity with the ``-q`` and ``-v`` options
     # display all messages (useful to debug errors)
     $ php bin/console some-command -vvv
 
+.. versionadded:: 7.2
+
+    The ``--silent`` option was introduced in Symfony 7.2.
+
 The verbosity level can also be controlled globally for all commands with the
 ``SHELL_VERBOSITY`` environment variable (the ``-q`` and ``-v`` options still
 have more precedence over the value of ``SHELL_VERBOSITY``):
@@ -30,6 +37,7 @@ have more precedence over the value of ``SHELL_VERBOSITY``):
 =====================  =========================  ===========================================
 Console option         ``SHELL_VERBOSITY`` value  Equivalent PHP constant
 =====================  =========================  ===========================================
+``--silent``           ``-2``                     ``OutputInterface::VERBOSITY_SILENT``
 ``-q`` or ``--quiet``  ``-1``                     ``OutputInterface::VERBOSITY_QUIET``
 (none)                 ``0``                      ``OutputInterface::VERBOSITY_NORMAL``
 ``-v``                 ``1``                      ``OutputInterface::VERBOSITY_VERBOSE``
@@ -41,24 +49,25 @@ It is possible to print a message in a command for only a specific verbosity
 level. For example::
 
     // ...
+    use Symfony\Component\Console\Attribute\Argument;
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
     use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
 
-    class CreateUserCommand extends Command
+    #[AsCommand(name: 'app:create-user')]
+    class CreateUserCommand
     {
-        // ...
-
-        public function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(OutputInterface $output, #[Argument] string $username, #[Argument] string $password): int
         {
             $user = new User(...);
 
             $output->writeln([
-                'Username: '.$input->getArgument('username'),
-                'Password: '.$input->getArgument('password'),
+                'Username: '.$username,
+                'Password: '.$password,
             ]);
 
-            // available methods: ->isQuiet(), ->isVerbose(), ->isVeryVerbose(), ->isDebug()
+            // available methods: ->isSilent(), ->isQuiet(), ->isVerbose(), ->isVeryVerbose(), ->isDebug()
             if ($output->isVerbose()) {
                 $output->writeln('User class: '.$user::class);
             }
@@ -73,10 +82,19 @@ level. For example::
         }
     }
 
-When the quiet level is used, all output is suppressed as the default
+.. versionadded:: 7.2
+
+    The ``isSilent()`` method was introduced in Symfony 7.2.
+
+When the silent or quiet level are used, all output is suppressed as the default
 :method:`Symfony\\Component\\Console\\Output\\Output::write` method returns
 without actually printing.
 
+.. tip::
+
+    When using the ``silent`` verbosity, errors won't be displayed in the console
+    but they will still be logged through the :doc:`Symfony logger </logging>` integration.
+
 .. tip::
 
     The MonologBridge provides a :class:`Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler`
diff --git a/contributing/code/pull_requests.rst b/contributing/code/pull_requests.rst
index 548fc6c190c..6b40e940dfb 100644
--- a/contributing/code/pull_requests.rst
+++ b/contributing/code/pull_requests.rst
@@ -31,7 +31,7 @@ Before working on Symfony, setup a friendly environment with the following
 software:
 
 * Git;
-* PHP version 8.1 or above.
+* PHP version 8.2 or above.
 
 Configure Git
 ~~~~~~~~~~~~~
@@ -132,7 +132,7 @@ work:
   branch (you can find them on the `Symfony releases page`_). E.g. if you
   found a bug introduced in ``v5.1.10``, you need to work on ``5.4``.
 
-* ``7.1``, if you are adding a new feature.
+* ``7.2``, if you are adding a new feature.
 
   The only exception is when a new :doc:`major Symfony version </contributing/community/releases>`
   (5.0, 6.0, etc.) comes out every two years. Because of the
diff --git a/contributing/code/tests.rst b/contributing/code/tests.rst
index e6af1170e3d..060e3eda02b 100644
--- a/contributing/code/tests.rst
+++ b/contributing/code/tests.rst
@@ -32,7 +32,7 @@ tests, such as Doctrine, Twig and Monolog. To do so,
 
     .. code-block:: terminal
 
-        $ COMPOSER_ROOT_VERSION=6.4.x-dev composer update
+        $ COMPOSER_ROOT_VERSION=7.2.x-dev composer update
 
 .. _running:
 
diff --git a/contributing/documentation/format.rst b/contributing/documentation/format.rst
index ef17b55011e..3318df50841 100644
--- a/contributing/documentation/format.rst
+++ b/contributing/documentation/format.rst
@@ -243,39 +243,39 @@ If you are documenting a brand new feature, a change or a deprecation that's
 been made in Symfony, you should precede your description of the change with
 the corresponding directive and a short description:
 
-For a new feature or a behavior change use the ``.. versionadded:: 6.x``
+For a new feature or a behavior change use the ``.. versionadded:: 7.x``
 directive:
 
 .. code-block:: rst
 
-    .. versionadded:: 6.2
+    .. versionadded:: 7.2
 
-        ... ... ... was introduced in Symfony 6.2.
+        ... ... ... was introduced in Symfony 7.2.
 
 If you are documenting a behavior change, it may be helpful to *briefly*
 describe how the behavior has changed:
 
 .. code-block:: rst
 
-    .. versionadded:: 6.2
+    .. versionadded:: 7.2
 
-       ... ... ... was introduced in Symfony 6.2. Prior to this,
+       ... ... ... was introduced in Symfony 7.2. Prior to this,
        ... ... ... ... ... ... ... ... .
 
-For a deprecation use the ``.. deprecated:: 6.x`` directive:
+For a deprecation use the ``.. deprecated:: 7.x`` directive:
 
 .. code-block:: rst
 
-    .. deprecated:: 6.2
+    .. deprecated:: 7.2
 
-        ... ... ... was deprecated in Symfony 6.2.
+        ... ... ... was deprecated in Symfony 7.2.
 
-Whenever a new major version of Symfony is released (e.g. 6.0, 7.0, etc), a new
+Whenever a new major version of Symfony is released (e.g. 8.0, 9.0, etc), a new
 branch of the documentation is created from the ``x.4`` branch of the previous
 major version. At this point, all the ``versionadded`` and ``deprecated`` tags
 for Symfony versions that have a lower major version will be removed. For
-example, if Symfony 6.0 were released today, 5.0 to 5.4 ``versionadded`` and
-``deprecated`` tags would be removed from the new ``6.0`` branch.
+example, if Symfony 8.0 were released today, 7.0 to 7.4 ``versionadded`` and
+``deprecated`` tags would be removed from the new ``8.0`` branch.
 
 .. _`reStructuredText`: https://docutils.sourceforge.io/rst.html
 .. _`Docs Builder`: https://github.com/symfony-tools/docs-builder
diff --git a/controller.rst b/controller.rst
index 43785329efb..5b0b77b35b9 100644
--- a/controller.rst
+++ b/controller.rst
@@ -230,10 +230,6 @@ command:
 
     You can read more about this attribute in :ref:`autowire-attribute`.
 
-    .. versionadded:: 6.1
-
-        The ``#[Autowire]`` attribute was introduced in Symfony 6.1.
-
 Like with all services, you can also use regular
 :ref:`constructor injection <services-constructor-injection>` in your
 controllers.
@@ -375,6 +371,11 @@ The ``MapQueryParameter`` attribute supports the following argument types:
 * ``float``
 * ``int``
 * ``string``
+* Objects that extend :class:`Symfony\\Component\\Uid\\AbstractUid`
+
+.. versionadded:: 7.3
+
+    Support for ``AbstractUid`` objects was introduced in Symfony 7.3.
 
 ``#[MapQueryParameter]`` can take an optional argument called ``filter``. You can use the
 `Validate Filters`_ constants defined in PHP::
@@ -393,11 +394,6 @@ The ``MapQueryParameter`` attribute supports the following argument types:
         // ...
     }
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryParameter` attribute
-    was introduced in Symfony 6.3.
-
 .. _controller-mapping-query-string:
 
 Mapping The Whole Query String
@@ -461,30 +457,41 @@ HTTP status to return if the validation fails::
 
 The default status code returned if the validation fails is 404.
 
-If you need a valid DTO even when the request query string is empty, set a
-default value for your controller arguments::
+If you want to map your object to a nested array in your query using a specific key,
+set the ``key`` option in the ``#[MapQueryString]`` attribute::
 
-    use App\Model\UserDto;
+    use App\Model\SearchDto;
     use Symfony\Component\HttpFoundation\Response;
     use Symfony\Component\HttpKernel\Attribute\MapQueryString;
 
     // ...
 
     public function dashboard(
-        #[MapQueryString] UserDto $userDto = new UserDto()
+        #[MapQueryString(key: 'search')] SearchDto $searchDto
     ): Response
     {
         // ...
     }
 
-.. versionadded:: 6.3
+.. versionadded:: 7.3
 
-    The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapQueryString` attribute
-    was introduced in Symfony 6.3.
+    The ``key`` option of ``#[MapQueryString]`` was introduced in Symfony 7.3.
 
-.. versionadded:: 6.4
+If you need a valid DTO even when the request query string is empty, set a
+default value for your controller arguments::
+
+    use App\Model\UserDto;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\HttpKernel\Attribute\MapQueryString;
 
-    The ``validationFailedStatusCode`` parameter was introduced in Symfony 6.4.
+    // ...
+
+    public function dashboard(
+        #[MapQueryString] UserDto $userDto = new UserDto()
+    ): Response
+    {
+        // ...
+    }
 
 .. _controller-mapping-request-payload:
 
@@ -583,14 +590,137 @@ if you want to map a nested array of specific DTOs::
         ) {}
     }
 
-.. versionadded:: 6.3
+Instead of returning an array of DTO objects, you can tell Symfony to transform
+each DTO object into an array and return something like this:
+
+.. code-block:: json
+
+    [
+        {
+            "firstName": "John",
+            "lastName": "Smith",
+            "age": 28
+        },
+        {
+            "firstName": "Jane",
+            "lastName": "Doe",
+            "age": 30
+        }
+    ]
+
+To do so, map the parameter as an array and configure the type of each element
+using the ``type`` option of the attribute::
+
+    public function dashboard(
+        #[MapRequestPayload(type: UserDto::class)] array $users
+    ): Response
+    {
+        // ...
+    }
+
+.. versionadded:: 7.1
+
+    The ``type`` option of ``#[MapRequestPayload]`` was introduced in Symfony 7.1.
 
-    The :class:`Symfony\\Component\\HttpKernel\\Attribute\\MapRequestPayload` attribute
-    was introduced in Symfony 6.3.
+.. _controller_map-uploaded-file:
 
-.. versionadded:: 6.4
+Mapping Uploaded Files
+~~~~~~~~~~~~~~~~~~~~~~
 
-    The ``validationFailedStatusCode`` parameter was introduced in Symfony 6.4.
+Symfony provides an attribute called ``#[MapUploadedFile]`` to map one or more
+``UploadedFile`` objects to controller arguments::
+
+    namespace App\Controller;
+
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\HttpFoundation\File\UploadedFile;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\HttpKernel\Attribute\MapUploadedFile;
+    use Symfony\Component\Routing\Attribute\Route;
+
+    class UserController extends AbstractController
+    {
+        #[Route('/user/picture', methods: ['PUT'])]
+        public function changePicture(
+            #[MapUploadedFile] UploadedFile $picture,
+        ): Response {
+            // ...
+        }
+    }
+
+In this example, the associated :doc:`argument resolver <controller/value_resolver>`
+fetches the ``UploadedFile`` based on the argument name (``$picture``). If no file
+is submitted, an ``HttpException`` is thrown. You can change this by making the
+controller argument nullable:
+
+.. code-block:: php-attributes
+
+    #[MapUploadedFile]
+    ?UploadedFile $document
+
+The ``#[MapUploadedFile]`` attribute also allows to pass a list of constraints
+to apply to the uploaded file::
+
+    namespace App\Controller;
+
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\HttpFoundation\File\UploadedFile;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\HttpKernel\Attribute\MapUploadedFile;
+    use Symfony\Component\Routing\Attribute\Route;
+    use Symfony\Component\Validator\Constraints as Assert;
+
+    class UserController extends AbstractController
+    {
+        #[Route('/user/picture', methods: ['PUT'])]
+        public function changePicture(
+            #[MapUploadedFile([
+                new Assert\File(mimeTypes: ['image/png', 'image/jpeg']),
+                new Assert\Image(maxWidth: 3840, maxHeight: 2160),
+            ])]
+            UploadedFile $picture,
+        ): Response {
+            // ...
+        }
+    }
+
+The validation constraints are checked before injecting the ``UploadedFile`` into
+the controller argument. If there's a constraint violation, an ``HttpException``
+is thrown and the controller's action is not executed.
+
+If you need to upload a collection of files, map them to an array or a variadic
+argument. The given constraint will be applied to all files and if any of them
+fails, an ``HttpException`` is thrown:
+
+.. code-block:: php-attributes
+
+    #[MapUploadedFile(new Assert\File(mimeTypes: ['application/pdf']))]
+    array $documents
+
+    #[MapUploadedFile(new Assert\File(mimeTypes: ['application/pdf']))]
+    UploadedFile ...$documents
+
+Use the ``name`` option to rename the uploaded file to a custom value:
+
+.. code-block:: php-attributes
+
+    #[MapUploadedFile(name: 'something-else')]
+    UploadedFile $document
+
+In addition, you can change the status code of the HTTP exception thrown when
+there are constraint violations:
+
+.. code-block:: php-attributes
+
+    #[MapUploadedFile(
+        constraints: new Assert\File(maxSize: '2M'),
+        validationFailedStatusCode: Response::HTTP_REQUEST_ENTITY_TOO_LARGE
+    )]
+    UploadedFile $document
+
+.. versionadded:: 7.1
+
+    The ``#[MapUploadedFile]`` attribute was introduced in Symfony 7.1.
 
 Managing the Session
 --------------------
@@ -773,11 +903,6 @@ The ``file()`` helper provides some arguments to configure its behavior::
 Sending Early Hints
 ~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    The Early Hints helper of the ``AbstractController`` was introduced
-    in Symfony 6.3.
-
 `Early hints`_ tell the browser to start downloading some assets even before the
 application sends the response content. This improves perceived performance
 because the browser can prefetch resources that will be needed once the full
diff --git a/controller/error_pages.rst b/controller/error_pages.rst
index fc36b88779a..06087837437 100644
--- a/controller/error_pages.rst
+++ b/controller/error_pages.rst
@@ -154,7 +154,8 @@ automatically when installing ``symfony/framework-bundle``):
         # config/routes/framework.yaml
         when@dev:
             _errors:
-                resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
+                resource: '@FrameworkBundle/Resources/config/routing/errors.php'
+                type:     php
                 prefix:   /_error
 
     .. code-block:: xml
@@ -167,7 +168,7 @@ automatically when installing ``symfony/framework-bundle``):
                 https://symfony.com/schema/routing/routing-1.0.xsd">
 
             <when env="dev">
-                <import resource="@FrameworkBundle/Resources/config/routing/errors.xml" prefix="/_error"/>
+                <import resource="@FrameworkBundle/Resources/config/routing/errors.php" type="php" prefix="/_error"/>
             </when>
         </routes>
 
@@ -178,7 +179,7 @@ automatically when installing ``symfony/framework-bundle``):
 
         return function (RoutingConfigurator $routes): void {
             if ('dev' === $routes->env()) {
-                $routes->import('@FrameworkBundle/Resources/config/routing/errors.xml')
+                $routes->import('@FrameworkBundle/Resources/config/routing/errors.php', 'php')
                     ->prefix('/_error')
                 ;
             }
@@ -191,6 +192,11 @@ need to replace ``http://localhost/`` by the host used in your local setup):
 * ``http://localhost/_error/{statusCode}`` for HTML
 * ``http://localhost/_error/{statusCode}.{format}`` for any other format
 
+.. versionadded:: 7.3
+
+    The ``errors.php`` file was introduced in Symfony 7.3.
+    Previously, you had to import ``errors.xml``
+
 .. _overriding-non-html-error-output:
 
 Overriding Error output for non-HTML formats
@@ -336,3 +342,50 @@ time and again, you can have just one (or several) listeners deal with them.
     your application (like :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException`)
     and takes measures like redirecting the user to the login page, logging them
     out and other things.
+
+Dumping Error Pages as Static HTML Files
+----------------------------------------
+
+.. versionadded:: 7.3
+
+    The feature to dump error pages into static HTML files was introduced in Symfony 7.3.
+
+If an error occurs before reaching your Symfony application, web servers display
+their own default error pages instead of your custom ones. Dumping your application's
+error pages to static HTML ensures users always see your defined pages and improves
+performance by allowing the server to deliver errors instantly without calling
+your application.
+
+Symfony provides the following command to turn your error pages into static HTML files:
+
+.. code-block:: terminal
+
+    # the first argument is the path where the HTML files are stored
+    $ APP_ENV=prod php bin/console error:dump var/cache/prod/error_pages/
+
+    # by default, it generates the pages of all 4xx and 5xx errors, but you can
+    # pass a list of HTTP status codes to only generate those
+    $ APP_ENV=prod php bin/console error:dump var/cache/prod/error_pages/ 401 403 404 500
+
+You must also configure your web server to use these generated pages. For example,
+if you use Nginx:
+
+.. code-block:: nginx
+
+    # /etc/nginx/conf.d/example.com.conf
+    server {
+        # Existing server configuration
+        # ...
+
+        # Serve static error pages
+        error_page 400 /error_pages/400.html;
+        error_page 401 /error_pages/401.html;
+        # ...
+        error_page 510 /error_pages/510.html;
+        error_page 511 /error_pages/511.html;
+
+        location ^~ /error_pages/ {
+            root /path/to/your/symfony/var/cache/error_pages;
+            internal; # prevent direct URL access
+        }
+    }
diff --git a/controller/service.rst b/controller/service.rst
index 88af093ff29..cf83e066a19 100644
--- a/controller/service.rst
+++ b/controller/service.rst
@@ -7,11 +7,65 @@ and your controllers extend the `AbstractController`_ class, they *are* automati
 registered as services. This means you can use dependency injection like any
 other normal service.
 
-If your controllers don't extend the `AbstractController`_ class, you must
-explicitly mark your controller services as ``public``. Alternatively, you can
-apply the ``controller.service_arguments`` tag to your controller services. This
-will make the tagged services ``public`` and will allow you to inject services
-in method parameters:
+If you prefer to not extend the ``AbstractController`` class, you can register
+your controllers as services in several ways:
+
+#. Using the ``#[Route]`` attribute;
+#. Using the ``#[AsController]`` attribute;
+#. Using the ``controller.service_arguments`` service tag.
+
+Using the ``#[Route]`` Attribute
+--------------------------------
+
+When using :ref:`the #[Route] attribute <routing-route-attributes>` to define
+routes on any PHP class, Symfony treats that class as a controller. It registers
+it as a public, non-lazy service and enables service argument injection in all
+its methods.
+
+This is the simplest and recommended way to register controllers as services
+when not extending the base controller class.
+
+.. versionadded:: 7.3
+
+    The feature to register controllers as services when using the ``#[Route]``
+    attribute was introduced in Symfony 7.3.
+
+Using the ``#[AsController]`` Attribute
+---------------------------------------
+
+If you prefer, you can use the ``#[AsController]`` PHP attribute to automatically
+apply the ``controller.service_arguments`` tag to your controller services::
+
+    // src/Controller/HelloController.php
+    namespace App\Controller;
+
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\HttpKernel\Attribute\AsController;
+    use Symfony\Component\Routing\Attribute\Route;
+
+    #[AsController]
+    class HelloController
+    {
+        #[Route('/hello', name: 'hello', methods: ['GET'])]
+        public function index(): Response
+        {
+            // ...
+        }
+    }
+
+.. tip::
+
+    When using the ``#[Route]`` attribute, Symfony already registers the controller
+    class as a service, so using the ``#[AsController]`` attribute is redundant.
+
+Using the ``controller.service_arguments`` Service Tag
+------------------------------------------------------
+
+If your controllers don't extend the `AbstractController`_ class and you don't
+use the ``#[AsController]`` or ``#[Route]`` attributes, you must register the
+controllers as public services manually and apply the ``controller.service_arguments``
+:doc:`service tag </service_container/tags>` to enable service injection in
+controller actions:
 
 .. configuration-block::
 
@@ -58,26 +112,6 @@ in method parameters:
             calls:
                 - [setContainer, ['@abstract_controller.locator']]
 
-If you prefer, you can use the ``#[AsController]`` PHP attribute to automatically
-apply the ``controller.service_arguments`` tag to your controller services::
-
-    // src/Controller/HelloController.php
-    namespace App\Controller;
-
-    use Symfony\Component\HttpFoundation\Response;
-    use Symfony\Component\HttpKernel\Attribute\AsController;
-    use Symfony\Component\Routing\Attribute\Route;
-
-    #[AsController]
-    class HelloController
-    {
-        #[Route('/hello', name: 'hello', methods: ['GET'])]
-        public function index(): Response
-        {
-            // ...
-        }
-    }
-
 Registering your controller as a service is the first step, but you also need to
 update your routing config to reference the service properly, so that Symfony
 knows to use it.
diff --git a/controller/upload_file.rst b/controller/upload_file.rst
index 941bd911a78..793cd26dd65 100644
--- a/controller/upload_file.rst
+++ b/controller/upload_file.rst
@@ -75,11 +75,11 @@ so Symfony doesn't try to get/set its value from the related entity::
                     // unmapped fields can't define their validation using attributes
                     // in the associated entity, so you can use the PHP constraint classes
                     'constraints' => [
-                        new File([
-                            'maxSize' => '1024k',
-                            'extensions' => ['pdf'],
-                            'extensionsMessage' => 'Please upload a valid PDF document',
-                        ])
+                        new File(
+                            maxSize: '1024k',
+                            extensions: ['pdf'],
+                            extensionsMessage: 'Please upload a valid PDF document',
+                        )
                     ],
                 ])
                 // ...
@@ -182,13 +182,24 @@ There are some important things to consider in the code of the above controller:
    users. This also applies to the files uploaded by your visitors. The ``UploadedFile``
    class provides methods to get the original file extension
    (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalExtension`),
-   the original file size (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getSize`)
-   and the original file name (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalName`).
+   the original file size (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getSize`),
+   the original file name (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalName`)
+   and the original file path (:method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::getClientOriginalPath`).
    However, they are considered *not safe* because a malicious user could tamper
    that information. That's why it's always better to generate a unique name and
    use the :method:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile::guessExtension`
    method to let Symfony guess the right extension according to the file MIME type;
 
+.. note::
+
+    If a directory was uploaded, ``getClientOriginalPath()`` will contain
+    the **webkitRelativePath** as provided by the browser. Otherwise this
+    value will be identical to ``getClientOriginalName()``.
+
+.. versionadded:: 7.1
+
+    The ``getClientOriginalPath()`` method was introduced in Symfony 7.1.
+
 You can use the following code to link to the PDF brochure of a product:
 
 .. code-block:: html+twig
diff --git a/controller/value_resolver.rst b/controller/value_resolver.rst
index f0f0db9aff1..835edcfbff9 100644
--- a/controller/value_resolver.rst
+++ b/controller/value_resolver.rst
@@ -75,10 +75,6 @@ Symfony ships with the following value resolvers in the
     The example above allows requesting only ``/cards/D`` and ``/cards/S``
     URLs and leads to 404 Not Found response in two other cases.
 
-    .. versionadded:: 6.1
-
-        The ``BackedEnumValueResolver`` and ``EnumRequirement`` were introduced in Symfony 6.1.
-
 :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestPayloadValueResolver`
     Maps the request payload or the query string into the type-hinted object.
 
@@ -87,10 +83,6 @@ Symfony ships with the following value resolvers in the
     or the :ref:`MapQueryString <controller-mapping-query-string>` attribute
     in order to use this resolver.
 
-    .. versionadded:: 6.3
-
-        The ``RequestPayloadValueResolver`` was introduced in Symfony 6.3.
-
 :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestAttributeValueResolver`
     Attempts to find a request attribute that matches the name of the argument.
 
@@ -110,16 +102,6 @@ Symfony ships with the following value resolvers in the
         receives when testing your application and using the
         :class:`Symfony\\Component\\Clock\\MockClock` implementation.
 
-    .. versionadded:: 6.1
-
-        The ``DateTimeValueResolver`` and the ``MapDateTime`` attribute were
-        introduced in Symfony 6.1.
-
-    .. versionadded:: 6.3
-
-        The use of the :doc:`Clock component </components/clock>` to generate the
-        ``DateTimeInterface`` object was introduced in Symfony 6.3.
-
 :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestValueResolver`
     Injects the current ``Request`` if type-hinted with ``Request`` or a class
     extending ``Request``.
@@ -159,10 +141,6 @@ Symfony ships with the following value resolvers in the
             }
         }
 
-    .. versionadded:: 6.1
-
-        The ``UidValueResolver`` was introduced in Symfony 6.1.
-
 :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\VariadicValueResolver`
     Verifies if the request data is an array and will add all of them to the
     argument list. When the action is called, the last (variadic) argument will
@@ -188,10 +166,6 @@ In addition, some components, bridges and official bundles provide other value r
     If the argument is not nullable and there is no logged in token, an ``HttpException``
     with status code 401 is thrown by the resolver to prevent access to the controller.
 
-    .. versionadded:: 6.3
-
-        The ``SecurityTokenValueResolver`` was introduced in Symfony 6.3.
-
 :class:`Symfony\\Bridge\\Doctrine\\ArgumentResolver\\EntityValueResolver`
     Automatically query for an entity and pass it as an argument to your controller.
 
@@ -215,10 +189,6 @@ In addition, some components, bridges and official bundles provide other value r
     To learn more about the use of the ``EntityValueResolver``, see the dedicated
     section :ref:`Automatically Fetching Objects <doctrine-entity-value-resolver>`.
 
-    .. versionadded:: 6.2
-
-        The ``EntityValueResolver`` was introduced in Symfony 6.2.
-
 PSR-7 Objects Resolver:
     Injects a Symfony HttpFoundation ``Request`` object created from a PSR-7 object
     of type ``Psr\Http\Message\ServerRequestInterface``,
@@ -264,10 +234,6 @@ lets you do this by "targeting" the resolver you want::
         }
     }
 
-.. versionadded:: 6.3
-
-    The ``ValueResolver`` attribute was introduced in Symfony 6.3.
-
 In the example above, the ``SessionValueResolver`` will be called first because
 it is targeted. The ``DefaultValueResolver`` will be called next if no value has
 been provided; that's why you can assign ``null`` as ``$session``'s default value.
@@ -301,13 +267,6 @@ object whenever a controller argument has a type implementing
         }
     }
 
-.. versionadded:: 6.2
-
-    The ``ValueResolverInterface`` was introduced in Symfony 6.2. Prior to
-    6.2, you had to use the
-    :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`,
-    which defines different methods.
-
 Adding a new value resolver requires creating a class that implements
 :class:`Symfony\\Component\\HttpKernel\\Controller\\ValueResolverInterface`
 and defining a service for it.
@@ -451,7 +410,7 @@ command to see which argument resolvers are present and in which order they run:
 
 .. code-block:: terminal
 
-    $ php bin/console debug:container debug.argument_resolver.inner --show-arguments
+    $ php bin/console debug:container debug.argument_resolver.inner
 
 You can also configure the name passed to the ``ValueResolver`` attribute to target
 your resolver. Otherwise it will default to the service's id.
@@ -497,8 +456,3 @@ You can then pass this name as ``ValueResolver``'s first argument to target your
             // ... do something with $id
         }
     }
-
-.. versionadded:: 6.3
-
-    The ``controller.targeted_value_resolver`` tag and ``AsTargetedValueResolver``
-    attribute were introduced in Symfony 6.3.
diff --git a/create_framework/http_kernel_httpkernel_class.rst b/create_framework/http_kernel_httpkernel_class.rst
index 05d9ad6d93e..158de638f8a 100644
--- a/create_framework/http_kernel_httpkernel_class.rst
+++ b/create_framework/http_kernel_httpkernel_class.rst
@@ -113,11 +113,6 @@ client; that's what the ``ResponseListener`` does::
 
     $dispatcher->addSubscriber(new HttpKernel\EventListener\ResponseListener('UTF-8'));
 
-If you want out of the box support for streamed responses, subscribe
-to ``StreamedResponseListener``::
-
-    $dispatcher->addSubscriber(new HttpKernel\EventListener\StreamedResponseListener());
-
 And in your controller, return a ``StreamedResponse`` instance instead of a
 ``Response`` instance.
 
diff --git a/create_framework/unit_testing.rst b/create_framework/unit_testing.rst
index f935a024b20..9c179cd3152 100644
--- a/create_framework/unit_testing.rst
+++ b/create_framework/unit_testing.rst
@@ -12,7 +12,7 @@ using `PHPUnit`_. At first, install PHPUnit as a development dependency:
 
 .. code-block:: terminal
 
-    $ composer require --dev phpunit/phpunit:^10.0
+    $ composer require --dev phpunit/phpunit:^11.0
 
 Then, create a PHPUnit configuration file in ``example.com/phpunit.xml.dist``:
 
@@ -21,7 +21,7 @@ Then, create a PHPUnit configuration file in ``example.com/phpunit.xml.dist``:
     <?xml version="1.0" encoding="UTF-8"?>
     <phpunit
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
+        xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.0/phpunit.xsd"
         backupGlobals="false"
         colors="true"
         bootstrap="vendor/autoload.php"
@@ -212,6 +212,6 @@ Symfony code.
 Now that we are confident (again) about the code we have written, we can
 safely think about the next batch of features we want to add to our framework.
 
-.. _`PHPUnit`: https://docs.phpunit.de/en/10.0/
-.. _`test doubles`: https://docs.phpunit.de/en/10.0/test-doubles.html
+.. _`PHPUnit`: https://docs.phpunit.de/en/11.0/
+.. _`test doubles`: https://docs.phpunit.de/en/11.0/test-doubles.html
 .. _`XDebug`: https://xdebug.org/
diff --git a/deployment/proxies.rst b/deployment/proxies.rst
index f72fe74aee7..4dad6f95fb1 100644
--- a/deployment/proxies.rst
+++ b/deployment/proxies.rst
@@ -22,7 +22,11 @@ Solution: ``setTrustedProxies()``
 ---------------------------------
 
 To fix this, you need to tell Symfony which reverse proxy IP addresses to trust
-and what headers your reverse proxy uses to send information:
+and what headers your reverse proxy uses to send information.
+
+You can do that by setting the ``SYMFONY_TRUSTED_PROXIES`` and ``SYMFONY_TRUSTED_HEADERS``
+environment variables on your machine. Alternatively, you can configure them
+using the following configuration options:
 
 .. configuration-block::
 
@@ -33,6 +37,8 @@ and what headers your reverse proxy uses to send information:
             # ...
             # the IP address (or range) of your proxy
             trusted_proxies: '192.0.0.1,10.0.0.0/8'
+            # shortcut for private IP address ranges of your proxy
+            trusted_proxies: 'private_ranges'
             # trust *all* "X-Forwarded-*" headers
             trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']
             # or, if your proxy instead uses the "Forwarded" header
@@ -53,6 +59,8 @@ and what headers your reverse proxy uses to send information:
             <framework:config>
                 <!-- the IP address (or range) of your proxy -->
                 <framework:trusted-proxies>192.0.0.1,10.0.0.0/8</framework:trusted-proxies>
+                <!-- shortcut for private IP address ranges of your proxy -->
+                <framework:trusted-proxies>private_ranges</framework:trusted-proxies>
 
                 <!-- trust *all* "X-Forwarded-*" headers -->
                 <framework:trusted-header>x-forwarded-for</framework:trusted-header>
@@ -75,6 +83,8 @@ and what headers your reverse proxy uses to send information:
             $framework
                 // the IP address (or range) of your proxy
                 ->trustedProxies('192.0.0.1,10.0.0.0/8')
+                // shortcut for private IP address ranges of your proxy
+                ->trustedProxies('private_ranges')
                 // trust *all* "X-Forwarded-*" headers (the ! prefix means to not trust those headers)
                 ->trustedHeaders(['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix'])
                 // or, if your proxy instead uses the "Forwarded" header
@@ -82,6 +92,16 @@ and what headers your reverse proxy uses to send information:
             ;
         };
 
+.. versionadded:: 7.1
+
+    ``private_ranges`` as a shortcut for private IP address ranges for the
+    ``trusted_proxies`` option was introduced in Symfony 7.1.
+
+.. versionadded:: 7.2
+
+    Support for the ``SYMFONY_TRUSTED_PROXIES`` and ``SYMFONY_TRUSTED_HEADERS``
+    environment variables was introduced in Symfony 7.2.
+
 .. danger::
 
     Enabling the ``Request::HEADER_X_FORWARDED_HOST`` option exposes the
@@ -132,9 +152,17 @@ In this case, you'll need to - *very carefully* - trust *all* proxies.
        framework:
            # ...
            # trust *all* requests (the 'REMOTE_ADDR' string is replaced at
-           # run time by $_SERVER['REMOTE_ADDR'])
+           # runtime by $_SERVER['REMOTE_ADDR'])
            trusted_proxies: '127.0.0.1,REMOTE_ADDR'
 
+           # you can also use the 'PRIVATE_SUBNETS' string, which is replaced at
+           # runtime by the IpUtils::PRIVATE_SUBNETS constant
+           # trusted_proxies: '127.0.0.1,PRIVATE_SUBNETS'
+
+.. versionadded:: 7.2
+
+    The support for the ``'PRIVATE_SUBNETS'`` string was introduced in Symfony 7.2.
+
 That's it! It's critical that you prevent traffic from all non-trusted sources.
 If you allow outside traffic, they could "spoof" their true IP address and
 other information.
diff --git a/doctrine.rst b/doctrine.rst
index ae7cb259628..6a1438322fa 100644
--- a/doctrine.rst
+++ b/doctrine.rst
@@ -62,10 +62,11 @@ The database connection information is stored as an environment variable called
 
     If the username, password, host or database name contain any character considered
     special in a URI (such as ``: / ? # [ ] @ ! $ & ' ( ) * + , ; =``),
-    you must encode them. See `RFC 3986`_ for the full list of reserved characters or
-    use the :phpfunction:`urlencode` function to encode them. In this case you need to
-    remove the ``resolve:`` prefix in ``config/packages/doctrine.yaml`` to avoid errors:
-    ``url: '%env(DATABASE_URL)%'``
+    you must encode them. See `RFC 3986`_ for the full list of reserved characters.
+    You can use the :phpfunction:`urlencode` function to encode them or
+    the :ref:`urlencode environment variable processor <urlencode_environment_variable_processor>`.
+    In this case you need to remove the ``resolve:`` prefix in ``config/packages/doctrine.yaml``
+    to avoid errors: ``url: '%env(DATABASE_URL)%'``
 
 Now that your connection parameters are setup, Doctrine can create the ``db_name``
 database for you:
@@ -83,6 +84,8 @@ affect how Doctrine functions.
     There are many other Doctrine commands. Run ``php bin/console list doctrine``
     to see a full list.
 
+.. _doctrine-adding-mapping:
+
 Creating an Entity Class
 ------------------------
 
@@ -90,8 +93,6 @@ Suppose you're building an application where products need to be displayed.
 Without even thinking about Doctrine or databases, you already know that
 you need a ``Product`` object to represent those products.
 
-.. _doctrine-adding-mapping:
-
 You can use the ``make:entity`` command to create this class and any fields you
 need. The command will ask you some questions - answer them like done below:
 
@@ -173,13 +174,6 @@ Whoa! You now have a new ``src/Entity/Product.php`` file::
     Confused why the price is an integer? Don't worry: this is just an example.
     But, storing prices as integers (e.g. 100 = $1 USD) can avoid rounding issues.
 
-.. note::
-
-    If you are using an SQLite database, you'll see the following error:
-    *PDOException: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL
-    column with default value NULL*. Add a ``nullable=true`` option to the
-    ``description`` property to fix the problem.
-
 .. warning::
 
     There is a `limit of 767 bytes for the index key prefix`_ when using
@@ -326,6 +320,13 @@ before, execute your migrations:
 
     $ php bin/console doctrine:migrations:migrate
 
+.. warning::
+
+    If you are using an SQLite database, you'll see the following error:
+    *PDOException: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL
+    column with default value NULL*. Add a ``nullable=true`` option to the
+    ``description`` property to fix the problem.
+
 This will only execute the *one* new migration file, because DoctrineMigrationsBundle
 knows that the first migration was already executed earlier. Behind the scenes, it
 manages a ``migration_versions`` table to track this.
@@ -619,10 +620,6 @@ the :ref:`doctrine-queries` section.
 Automatically Fetching Objects (EntityValueResolver)
 ----------------------------------------------------
 
-.. versionadded:: 6.2
-
-    Entity Value Resolver was introduced in Symfony 6.2.
-
 .. versionadded:: 2.7.1
 
     Autowiring of the ``EntityValueResolver`` was introduced in DoctrineBundle 2.7.1.
@@ -697,7 +694,7 @@ will automatically fetch them::
     /**
      * Perform a findOneBy() where the slug property matches {slug}.
      */
-    #[Route('/product/{slug}')]
+    #[Route('/product/{slug:product}')]
     public function showBySlug(Product $product): Response
     {
     }
@@ -711,14 +708,17 @@ Automatic fetching works in these situations:
   *all* of the wildcards in your route that are actually properties
   on your entity (non-properties are ignored).
 
-This behavior is enabled by default on all controllers. If you prefer, you can
-restrict this feature to only work on route wildcards called ``id`` to look for
-entities by primary key. To do so, set the option
-``doctrine.orm.controller_resolver.auto_mapping`` to ``false``.
+The ``{slug:product}`` syntax maps the route parameter named ``slug`` to the
+controller argument named ``$product``. It also hints the resolver to look up
+the corresponding ``Product`` object from the database using the slug.
 
-When ``auto_mapping`` is disabled, you can configure the mapping explicitly for
-any controller argument with the ``MapEntity`` attribute. You can even control
-the ``EntityValueResolver`` behavior by using the `MapEntity options`_ ::
+.. versionadded:: 7.1
+
+    Route parameter mapping was introduced in Symfony 7.1.
+
+You can also configure the mapping explicitly for any controller argument
+using the ``MapEntity`` attribute. You can even control the behavior of the
+``EntityValueResolver`` by using the `MapEntity options`_ ::
 
     // src/Controller/ProductController.php
     namespace App\Controller;
@@ -758,6 +758,20 @@ In the expression, the ``repository`` variable will be your entity's
 Repository class and any route wildcards - like ``{product_id}`` are
 available as variables.
 
+The repository method called in the expression can also return a list of entities.
+In that case, update the type of your controller argument::
+
+    #[Route('/posts_by/{author_id}')]
+    public function authorPosts(
+        #[MapEntity(class: Post::class, expr: 'repository.findBy({"author": author_id}, {}, 10)')]
+        iterable $posts
+    ): Response {
+    }
+
+.. versionadded:: 7.1
+
+    The mapping of the lists of entities was introduced in Symfony 7.1.
+
 This can also be used to help resolve multiple arguments::
 
     #[Route('/product/{id}/comments/{comment_id}')]
@@ -784,10 +798,31 @@ variable. Let's say you want the first or the last comment of a product dependin
     ): Response {
     }
 
-.. versionadded:: 6.4
+.. _doctrine-entity-value-resolver-resolve-target-entities:
+
+Fetch via Interfaces
+~~~~~~~~~~~~~~~~~~~~
+
+Suppose your ``Product`` class implements an interface called ``ProductInterface``.
+If you want to decouple your controllers from the concrete entity implementation,
+you can reference the entity by its interface instead.
 
-    The support for the ``request`` variable in expressions was introduced
-    in Symfony 6.4.
+To enable this, first configure the
+:doc:`resolve_target_entities option </doctrine/resolve_target_entity>`.
+Then, your controller can type-hint the interface, and the entity will be
+resolved automatically::
+
+    public function show(
+        #[MapEntity]
+        ProductInterface $product
+    ): Response {
+        // ...
+    }
+
+.. versionadded:: 7.3
+
+    Support for target entity resolution in the ``EntityValueResolver`` was
+    introduced Symfony 7.3
 
 MapEntity Options
 ~~~~~~~~~~~~~~~~~
@@ -820,18 +855,6 @@ control behavior:
         ): Response {
         }
 
-``exclude``
-    Configures the properties that should be used in the ``findOneBy()``
-    method by *excluding* one or more properties so that not *all* are used::
-
-        #[Route('/product/{slug}/{date}')]
-        public function show(
-            #[MapEntity(exclude: ['date'])]
-            Product $product,
-            \DateTime $date
-        ): Response {
-        }
-
 ``stripNull``
     If true, then when ``findOneBy()`` is used, any values that are
     ``null`` will not be used for the query.
@@ -854,6 +877,21 @@ control behavior:
 ``disabled``
     If true, the ``EntityValueResolver`` will not try to replace the argument.
 
+``message``
+    An optional custom message displayed when there's a :class:`Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException`,
+    but **only in the development environment** (you won't see this message in production)::
+
+        #[Route('/product/{product_id}')]
+        public function show(
+            #[MapEntity(id: 'product_id', message: 'The product does not exist')]
+            Product $product
+        ): Response {
+        }
+
+.. versionadded:: 7.1
+
+    The ``message`` option was introduced in Symfony 7.1.
+
 Updating an Object
 ------------------
 
@@ -1096,12 +1134,10 @@ Learn more
 
     doctrine/associations
     doctrine/events
-    doctrine/registration_form
     doctrine/custom_dql_functions
     doctrine/dbal
     doctrine/multiple_entity_managers
     doctrine/resolve_target_entity
-    doctrine/reverse_engineering
     testing/database
 
 .. _`Doctrine`: https://www.doctrine-project.org/
diff --git a/doctrine/events.rst b/doctrine/events.rst
index 3f8f93bc2ee..accf424083a 100644
--- a/doctrine/events.rst
+++ b/doctrine/events.rst
@@ -34,7 +34,7 @@ to learn everything about them.
 
 .. seealso::
 
-    This article covers listeners and subscribers for Doctrine ORM. If you are
+    This article covers listeners for Doctrine ORM. If you are
     using ODM for MongoDB, read the `DoctrineMongoDBBundle documentation`_.
 
 Doctrine Lifecycle Callbacks
@@ -317,7 +317,7 @@ listener in the Symfony application by creating a new service for it and
                         # this is the only required option for the lifecycle listener tag
                         event: 'postPersist'
 
-                        # listeners can define their priority in case multiple subscribers or listeners are associated
+                        # listeners can define their priority in case listeners are associated
                         # to the same event (default priority = 0; higher numbers = listener is run earlier)
                         priority: 500
 
@@ -335,7 +335,7 @@ listener in the Symfony application by creating a new service for it and
 
                 <!--
                     * 'event' is the only required option that defines the lifecycle listener
-                    * 'priority': used when multiple subscribers or listeners are associated to the same event
+                    * 'priority': used when multiple listeners are associated to the same event
                     *             (default priority = 0; higher numbers = listener is run earlier)
                     * 'connection': restricts the listener to a specific Doctrine connection
                 -->
@@ -364,7 +364,7 @@ listener in the Symfony application by creating a new service for it and
                     // this is the only required option for the lifecycle listener tag
                     'event' => 'postPersist',
 
-                    // listeners can define their priority in case multiple subscribers or listeners are associated
+                    // listeners can define their priority in case multiple listeners are associated
                     // to the same event (default priority = 0; higher numbers = listener is run earlier)
                     'priority' => 500,
 
@@ -378,28 +378,11 @@ listener in the Symfony application by creating a new service for it and
 
     The `AsDoctrineListener`_ attribute was introduced in DoctrineBundle 2.8.0.
 
-.. tip::
-
-    Symfony loads (and instantiates) Doctrine listeners only when the related
-    Doctrine event is actually fired; whereas Doctrine subscribers are always
-    loaded (and instantiated) by Symfony, making them less performant.
-
 .. tip::
 
     The value of the ``connection`` option can also be a
     :ref:`configuration parameter <configuration-parameters>`.
 
-Doctrine Lifecycle Subscribers
-------------------------------
-
-.. deprecated:: 6.3
-
-    Lifecycle subscribers are deprecated starting from Symfony 6.3.
-
-This was another way of listening to events provided by Doctrine. However, they
-were deprecated in Symfony 6.3 and it's no longer recommended to use them.
-Instead, use any of the other alternatives shown above.
-
 .. _`Doctrine`: https://www.doctrine-project.org/
 .. _`lifecycle events`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/events.html#lifecycle-events
 .. _`official docs about Doctrine events`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/events.html
diff --git a/doctrine/registration_form.rst b/doctrine/registration_form.rst
deleted file mode 100644
index 7063b7157a4..00000000000
--- a/doctrine/registration_form.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-How to Implement a Registration Form
-====================================
-
-This article has been removed because it only explained things that are
-already explained in other articles. Specifically, to implement a registration
-form you must:
-
-#. :ref:`Define a class to represent users <create-user-class>`;
-#. :doc:`Create a form </forms>` to ask for the registration information (you can
-   generate this with the ``make:registration-form`` command provided by the `MakerBundle`_);
-#. Create :doc:`a controller </controller>` to :ref:`process the form <processing-forms>`;
-#. :ref:`Protect some parts of your application <security-access-control>` so that
-   only registered users can access to them.
-
-.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html
diff --git a/doctrine/resolve_target_entity.rst b/doctrine/resolve_target_entity.rst
index 5ae6475a957..1495f475628 100644
--- a/doctrine/resolve_target_entity.rst
+++ b/doctrine/resolve_target_entity.rst
@@ -1,39 +1,45 @@
-How to Define Relationships with Abstract Classes and Interfaces
-================================================================
+Referencing Entities with Abstract Classes and Interfaces
+=========================================================
 
-One of the goals of bundles is to create discrete bundles of functionality
-that do not have many (if any) dependencies, allowing you to use that
-functionality in other applications without including unnecessary items.
+In applications where functionality is organized in layers or modules with
+minimal concrete dependencies, such as monoliths split into multiple modules,
+it can be challenging to avoid tight coupling between entities.
 
-Doctrine 2.2 includes a new utility called the ``ResolveTargetEntityListener``,
-that functions by intercepting certain calls inside Doctrine and rewriting
-``targetEntity`` parameters in your metadata mapping at runtime. It means that
-in your bundle you are able to use an interface or abstract class in your
-mappings and expect correct mapping to a concrete entity at runtime.
+Doctrine provides a utility called the ``ResolveTargetEntityListener`` to solve
+this issue. It works by intercepting certain calls within Doctrine and rewriting
+``targetEntity`` parameters in your metadata mapping at runtime. This allows you
+to reference an interface or abstract class in your mappings and have it resolved
+to a concrete entity at runtime.
 
-This functionality allows you to define relationships between different entities
-without making them hard dependencies.
+This makes it possible to define relationships between entities without
+creating hard dependencies. This feature also works with the ``EntityValueResolver``
+:ref:`as explained in the main Doctrine article <doctrine-entity-value-resolver-resolve-target-entities>`.
+
+.. versionadded:: 7.3
+
+    Support for target entity resolution in the ``EntityValueResolver`` was
+    introduced Symfony 7.3
 
 Background
 ----------
 
-Suppose you have an InvoiceBundle which provides invoicing functionality
-and a CustomerBundle that contains customer management tools. You want
-to keep these separated, because they can be used in other systems without
-each other, but for your application you want to use them together.
+Suppose you have an application with two modules: an Invoice module that
+provides invoicing functionality, and a Customer module that handles customer
+management. You want to keep these modules decoupled, so that neither is aware
+of the other's implementation details.
 
-In this case, you have an ``Invoice`` entity with a relationship to a
-non-existent object, an ``InvoiceSubjectInterface``. The goal is to get
-the ``ResolveTargetEntityListener`` to replace any mention of the interface
-with a real object that implements that interface.
+In this case, your ``Invoice`` entity has a relationship to the interface
+``InvoiceSubjectInterface``. Since interfaces are not valid Doctrine entities,
+the goal is to use the ``ResolveTargetEntityListener`` to replace all
+references to this interface with a concrete class that implements it.
 
 Set up
 ------
 
-This article uses the following two basic entities (which are incomplete for
-brevity) to explain how to set up and use the ``ResolveTargetEntityListener``.
+This article uses two basic (incomplete) entities to demonstrate how to set up
+and use the ``ResolveTargetEntityListener``.
 
-A Customer entity::
+A ``Customer`` entity::
 
     // src/Entity/Customer.php
     namespace App\Entity;
@@ -50,7 +56,7 @@ A Customer entity::
         // are already implemented in the BaseCustomer
     }
 
-An Invoice entity::
+An ``Invoice`` entity::
 
     // src/Entity/Invoice.php
     namespace App\Entity;
@@ -58,9 +64,6 @@ An Invoice entity::
     use App\Model\InvoiceSubjectInterface;
     use Doctrine\ORM\Mapping as ORM;
 
-    /**
-     * Represents an Invoice.
-     */
     #[ORM\Entity]
     #[ORM\Table(name: 'invoice')]
     class Invoice
@@ -69,7 +72,7 @@ An Invoice entity::
         protected InvoiceSubjectInterface $subject;
     }
 
-An InvoiceSubjectInterface::
+The interface representing the subject used in the invoice::
 
     // src/Model/InvoiceSubjectInterface.php
     namespace App\Model;
@@ -89,8 +92,8 @@ An InvoiceSubjectInterface::
         public function getName(): string;
     }
 
-Next, you need to configure the listener, which tells the DoctrineBundle
-about the replacement:
+Now configure the ``resolve_target_entities`` option to tell Doctrine
+how to replace the interface with the concrete class:
 
 .. configuration-block::
 
@@ -140,7 +143,6 @@ about the replacement:
 Final Thoughts
 --------------
 
-With the ``ResolveTargetEntityListener``, you are able to decouple your
-bundles, keeping them usable by themselves, but still being able to
-define relationships between different objects. By using this method,
-your bundles will end up being easier to maintain independently.
+Using ``ResolveTargetEntityListener`` allows you to decouple your modules
+while still defining relationships between their entities. This makes your
+codebase more modular and easier to maintain over time.
diff --git a/doctrine/reverse_engineering.rst b/doctrine/reverse_engineering.rst
deleted file mode 100644
index 7f1ea793958..00000000000
--- a/doctrine/reverse_engineering.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-How to Generate Entities from an Existing Database
-==================================================
-
-.. warning::
-
-    The ``doctrine:mapping:import`` command used to generate Doctrine entities
-    from existing databases was deprecated by Doctrine in 2019 and there's no
-    replacement for it.
-
-    Instead, you can use the ``make:entity`` command from `Symfony Maker Bundle`_
-    to help you generate the code of your Doctrine entities. This command
-    requires manual supervision because it doesn't generate entities from
-    existing databases.
-
-.. _`Symfony Maker Bundle`: https://symfony.com/bundles/SymfonyMakerBundle/current/index.html
diff --git a/emoji.rst b/emoji.rst
new file mode 100644
index 00000000000..551497f0c76
--- /dev/null
+++ b/emoji.rst
@@ -0,0 +1,173 @@
+Working with Emojis
+===================
+
+.. versionadded:: 7.1
+
+    The emoji component was introduced in Symfony 7.1.
+
+Symfony provides several utilities to work with emoji characters and sequences
+from the `Unicode CLDR dataset`_. They are available via the Emoji component,
+which you must first install in your application:
+
+.. _installation:
+
+.. code-block:: terminal
+
+    $ composer require symfony/emoji
+
+.. include:: /components/require_autoload.rst.inc
+
+The data needed to store the transliteration of all emojis (~5,000) into all
+languages take a considerable disk space.
+
+If you need to save disk space (e.g. because you deploy to some service with tight
+size constraints), run this command (e.g. as an automated script after ``composer install``)
+to compress the internal Symfony emoji data files using the PHP ``zlib`` extension:
+
+.. code-block:: terminal
+
+    # adjust the path to the 'compress' binary based on your application installation
+    $ php ./vendor/symfony/emoji/Resources/bin/compress
+
+.. _emoji-transliteration:
+
+Emoji Transliteration
+---------------------
+
+The ``EmojiTransliterator`` class offers a way to translate emojis into their
+textual representation in all languages based on the `Unicode CLDR dataset`_::
+
+    use Symfony\Component\Emoji\EmojiTransliterator;
+
+    // Describe emojis in English
+    $transliterator = EmojiTransliterator::create('en');
+    $transliterator->transliterate('Menus with 🍕 or 🍝');
+    // => 'Menus with pizza or spaghetti'
+
+    // Describe emojis in Ukrainian
+    $transliterator = EmojiTransliterator::create('uk');
+    $transliterator->transliterate('Menus with 🍕 or 🍝');
+    // => 'Menus with піца or спагеті'
+
+.. tip::
+
+    When using the :ref:`slugger <string-slugger>` from the String component,
+    you can combine it with the ``EmojiTransliterator`` to :ref:`slugify emojis <string-slugger-emoji>`.
+
+Transliterating Emoji Text Short Codes
+--------------------------------------
+
+Services like GitHub and Slack allows to include emojis in your messages using
+text short codes (e.g. you can add the ``:+1:`` code to render the 👍 emoji).
+
+Symfony also provides a feature to transliterate emojis into short codes and vice
+versa. The short codes are slightly different on each service, so you must pass
+the name of the service as an argument when creating the transliterator.
+
+GitHub Emoji Short Codes Transliteration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Convert emojis to GitHub short codes with the ``emoji-github`` locale::
+
+    $transliterator = EmojiTransliterator::create('emoji-github');
+    $transliterator->transliterate('Teenage 🐢 really love 🍕');
+    // => 'Teenage :turtle: really love :pizza:'
+
+Convert GitHub short codes to emojis with the ``github-emoji`` locale::
+
+    $transliterator = EmojiTransliterator::create('github-emoji');
+    $transliterator->transliterate('Teenage :turtle: really love :pizza:');
+    // => 'Teenage 🐢 really love 🍕'
+
+Gitlab Emoji Short Codes Transliteration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Convert emojis to Gitlab short codes with the ``emoji-gitlab`` locale::
+
+    $transliterator = EmojiTransliterator::create('emoji-gitlab');
+    $transliterator->transliterate('Breakfast with 🥝 or 🥛');
+    // => 'Breakfast with :kiwi: or :milk:'
+
+Convert Gitlab short codes to emojis with the ``gitlab-emoji`` locale::
+
+    $transliterator = EmojiTransliterator::create('gitlab-emoji');
+    $transliterator->transliterate('Breakfast with :kiwi: or :milk:');
+    // => 'Breakfast with 🥝 or 🥛'
+
+Slack Emoji Short Codes Transliteration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Convert emojis to Slack short codes with the ``emoji-slack`` locale::
+
+    $transliterator = EmojiTransliterator::create('emoji-slack');
+    $transliterator->transliterate('Menus with 🥗 or 🧆');
+    // => 'Menus with :green_salad: or :falafel:'
+
+Convert Slack short codes to emojis with the ``slack-emoji`` locale::
+
+    $transliterator = EmojiTransliterator::create('slack-emoji');
+    $transliterator->transliterate('Menus with :green_salad: or :falafel:');
+    // => 'Menus with 🥗 or 🧆'
+
+.. _text-emoji:
+
+Universal Emoji Short Codes Transliteration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you don't know which service was used to generate the short codes, you can use
+the ``text-emoji`` locale, which combines all codes from all services::
+
+    $transliterator = EmojiTransliterator::create('text-emoji');
+
+    // Github short codes
+    $transliterator->transliterate('Breakfast with :kiwi-fruit: or :milk-glass:');
+    // Gitlab short codes
+    $transliterator->transliterate('Breakfast with :kiwi: or :milk:');
+    // Slack short codes
+    $transliterator->transliterate('Breakfast with :kiwifruit: or :glass-of-milk:');
+
+    // all the above examples produce the same result:
+    // => 'Breakfast with 🥝 or 🥛'
+
+You can convert emojis to short codes with the ``emoji-text`` locale::
+
+    $transliterator = EmojiTransliterator::create('emoji-text');
+    $transliterator->transliterate('Breakfast with 🥝 or 🥛');
+    // => 'Breakfast with :kiwifruit: or :milk-glass:
+
+Inverse Emoji Transliteration
+-----------------------------
+
+Given the textual representation of an emoji, you can reverse it back to get the
+actual emoji thanks to the :ref:`emojify filter <reference-twig-filter-emojify>`:
+
+.. code-block:: twig
+
+    {{ 'I like :kiwi-fruit:'|emojify }} {# renders: I like 🥝 #}
+    {{ 'I like :kiwi:'|emojify }}       {# renders: I like 🥝 #}
+    {{ 'I like :kiwifruit:'|emojify }}  {# renders: I like 🥝 #}
+
+By default, ``emojify`` uses the :ref:`text catalog <text-emoji>`, which
+merges the emoji text codes of all services. If you prefer, you can select a
+specific catalog to use:
+
+.. code-block:: twig
+
+    {{ 'I :green-heart: this'|emojify }}                  {# renders: I 💚 this #}
+    {{ ':green_salad: is nice'|emojify('slack') }}        {# renders: 🥗 is nice #}
+    {{ 'My :turtle: has no name yet'|emojify('github') }} {# renders: My 🐢 has no name yet #}
+    {{ ':kiwi: is a great fruit'|emojify('gitlab') }}     {# renders: 🥝 is a great fruit #}
+
+Removing Emojis
+---------------
+
+The ``EmojiTransliterator`` can also be used to remove all emojis from a string,
+via the special ``strip`` locale::
+
+    use Symfony\Component\Emoji\EmojiTransliterator;
+
+    $transliterator = EmojiTransliterator::create('strip');
+    $transliterator->transliterate('🎉Hey!🥳 🎁Happy Birthday!🎁');
+    // => 'Hey! Happy Birthday!'
+
+.. _`Unicode CLDR dataset`: https://github.com/unicode-org/cldr
diff --git a/form/form_customization.rst b/form/form_customization.rst
index 1c23601a883..dc09aefe77d 100644
--- a/form/form_customization.rst
+++ b/form/form_customization.rst
@@ -103,6 +103,7 @@ That's why Symfony provides other Twig form helpers that render the value of
 each form field part without adding any HTML around it:
 
 * ``field_name()``
+* ``field_id()``
 * ``field_value()``
 * ``field_label()``
 * ``field_help()``
@@ -116,6 +117,7 @@ fields, so you no longer have to deal with form themes:
 
     <input
         name="{{ field_name(form.username) }}"
+        id="{{ field_id(form.username) }}"
         value="{{ field_value(form.username) }}"
         placeholder="{{ field_label(form.username) }}"
         class="form-control"
@@ -129,6 +131,10 @@ fields, so you no longer have to deal with form themes:
         {% endfor %}
     </select>
 
+.. versionadded:: 7.3
+
+    The ``field_id()`` helper was introduced in Symfony 7.3.
+
 Form Rendering Variables
 ------------------------
 
diff --git a/form/form_dependencies.rst b/form/form_dependencies.rst
deleted file mode 100644
index 96b067362ff..00000000000
--- a/form/form_dependencies.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-How to Access Services or Config from Inside a Form
-===================================================
-
-The content of this article is no longer relevant because in current Symfony
-versions, form classes are services by default and you can inject services in
-them using the :doc:`service autowiring </service_container/autowiring>` feature.
-
-Read the article about :doc:`creating custom form types </form/create_custom_field_type>`
-to see an example of how to inject the database service into a form type. In the
-same article you can also read about
-:ref:`configuration options for form types <form-type-config-options>`, which is
-another way of passing services to forms.
diff --git a/form/unit_testing.rst b/form/unit_testing.rst
index 2a53d43dd33..9603c5bc0d2 100644
--- a/form/unit_testing.rst
+++ b/form/unit_testing.rst
@@ -249,9 +249,4 @@ All you need to do is to implement the
 :method:`Symfony\\Bridge\\Twig\\Test\\FormLayoutTestCase::getTwigExtensions` and
 the :method:`Symfony\\Bridge\\Twig\\Test\\FormLayoutTestCase::getThemes` methods.
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Bridge\\Twig\\Test\\FormLayoutTestCase` class was
-    introduced in Symfony 6.4.
-
 .. _`PHPUnit data providers`: https://docs.phpunit.de/en/9.6/writing-tests-for-phpunit.html#data-providers
diff --git a/form/without_class.rst b/form/without_class.rst
index c0da3c9db5a..c31ff346170 100644
--- a/form/without_class.rst
+++ b/form/without_class.rst
@@ -96,12 +96,12 @@ but here's a short example::
     {
         $builder
             ->add('firstName', TextType::class, [
-                'constraints' => new Length(['min' => 3]),
+                'constraints' => new Length(min: 3),
             ])
             ->add('lastName', TextType::class, [
                 'constraints' => [
                     new NotBlank(),
-                    new Length(['min' => 3]),
+                    new Length(min: 3),
                 ],
             ])
         ;
@@ -153,10 +153,10 @@ This can be done by setting the ``constraints`` option in the
         $resolver->setDefaults([
             'data_class' => null,
             'constraints' => new Collection([
-                'firstName' => new Length(['min' => 3]),
+                'firstName' => new Length(min: 3),
                 'lastName' => [
                     new NotBlank(),
-                    new Length(['min' => 3]),
+                    new Length(min: 3),
                 ],
             ]),
         ]);
diff --git a/forms.rst b/forms.rst
index bea93edb25d..83065d7524b 100644
--- a/forms.rst
+++ b/forms.rst
@@ -298,13 +298,6 @@ Now that the form has been created, the next step is to render it::
 Internally, the ``render()`` method calls ``$form->createView()`` to
 transform the form into a *form view* instance.
 
-.. deprecated:: 6.2
-
-    Prior to Symfony 6.2, you had to use ``$this->render(..., ['form' => $form->createView()])``
-    or the ``renderForm()`` method to render the form. The ``renderForm()``
-    method is deprecated in favor of directly passing the ``FormInterface``
-    instance to ``render()``.
-
 Then, use some :ref:`form helper functions <reference-form-twig-functions>` to
 render the form contents:
 
@@ -971,7 +964,6 @@ Advanced Features:
 
     /controller/upload_file
     /security/csrf
-    /form/form_dependencies
     /form/create_custom_field_type
     /form/data_transformers
     /form/data_mappers
diff --git a/frontend/asset_mapper.rst b/frontend/asset_mapper.rst
index 6f045938339..912f645bf6a 100644
--- a/frontend/asset_mapper.rst
+++ b/frontend/asset_mapper.rst
@@ -1,10 +1,6 @@
 AssetMapper: Simple, Modern CSS & JS Management
 ===============================================
 
-.. versionadded:: 6.3
-
-    The AssetMapper component was introduced in Symfony 6.3.
-
 The AssetMapper component lets you write modern JavaScript and CSS without the complexity
 of using a bundler. Browsers *already* support many modern JavaScript features
 like the ``import`` statement and ES6 classes. And the HTTP/2 protocol means that
@@ -16,7 +12,7 @@ The component has two main features:
 * :ref:`Mapping & Versioning Assets <mapping-assets>`: All files inside of ``assets/``
   are made available publicly and **versioned**. You can reference the file
   ``assets/images/product.jpg`` in a Twig template with ``{{ asset('images/product.jpg') }}``.
-  The final URL will include a version hash, like ``/assets/images/product-3c16d9220694c0e56d8648f25e6035e9.jpg``.
+  The final URL will include a version hash, like ``/assets/images/product-3c16d92m.jpg``.
 
 * :ref:`Importmaps <importmaps-javascript>`: A native browser feature that makes it easier
   to use the JavaScript ``import`` statement (e.g. ``import { Modal } from 'bootstrap'``)
@@ -74,7 +70,7 @@ The path - ``images/duck.png`` - is relative to your mapped directory (``assets/
 This is known as the **logical path** to your asset.
 
 If you look at the HTML in your page, the URL will be something
-like: ``/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png``. If you change
+like: ``/assets/images/duck-3c16d92m.png``. If you change
 the file, the version part of the URL will also change automatically.
 
 .. _asset-mapper-compile-assets:
@@ -82,7 +78,7 @@ the file, the version part of the URL will also change automatically.
 Serving Assets in dev vs prod
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-In the ``dev`` environment, the URL ``/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png``
+In the ``dev`` environment, the URL ``/assets/images/duck-3c16d92m.png``
 is handled and returned by your Symfony app.
 
 For the ``prod`` environment, before deploy, you should run:
@@ -143,6 +139,28 @@ This will show you all the mapped paths and the assets inside of each:
 The "Logical Path" is the path to use when referencing the asset, like
 from a template.
 
+The ``debug:asset-map`` command provides several options to filter results:
+
+.. code-block:: terminal
+
+    # provide an asset name or dir to only show results that match it
+    $ php bin/console debug:asset-map bootstrap.js
+    $ php bin/console debug:asset-map style/
+
+    # provide an extension to only show that file type
+    $ php bin/console debug:asset-map --ext=css
+
+    # you can also only show assets in vendor/ dir or exclude any results from it
+    $ php bin/console debug:asset-map --vendor
+    $ php bin/console debug:asset-map --no-vendor
+
+    # you can also combine all filters (e.g. find bold web fonts in your own asset dirs)
+    $ php bin/console debug:asset-map bold --no-vendor --ext=woff2
+
+.. versionadded:: 7.2
+
+    The options to filter ``debug:asset-map`` results were introduced in Symfony 7.2.
+
 .. _importmaps-javascript:
 
 Importmaps & Writing JavaScript
@@ -197,6 +215,15 @@ to add any `npm package`_:
 
     $ php bin/console importmap:require bootstrap
 
+.. tip::
+
+    Add the ``--dry-run`` option to simulate package installation without actually
+    making any changes (e.g. ``php bin/console importmap:require bootstrap --dry-run``)
+
+    .. versionadded:: 7.3
+
+        The ``--dry-run`` option was introduced in Symfony 7.3.
+
 This adds the ``bootstrap`` package to your ``importmap.php`` file::
 
     // importmap.php
@@ -274,11 +301,6 @@ You can update your third-party packages to their current versions by running:
     $ php bin/console importmap:update bootstrap lodash
     $ php bin/console importmap:outdated bootstrap lodash
 
-.. versionadded:: 6.4
-
-    The ``importmap:install`` and ``importmap:outdated`` commands were introduced
-    in Symfony 6.4.
-
 Removing JavaScript Packages
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -317,9 +339,9 @@ outputs an `importmap`_:
 
     <script type="importmap">{
         "imports": {
-            "app": "/assets/app-4e986c1a2318dd050b1d47db8d856278.js",
-            "/assets/duck.js": "/assets/duck-1b7a64b3b3d31219c262cf72521a5267.js",
-            "bootstrap": "/assets/vendor/bootstrap/bootstrap.index-f0935445d9c6022100863214b519a1f2.js"
+            "app": "/assets/app-4e986c1a.js",
+            "/assets/duck.js": "/assets/duck-1b7a64b3.js",
+            "bootstrap": "/assets/vendor/bootstrap/bootstrap.index-f093544d.js"
         }
     }</script>
 
@@ -376,8 +398,8 @@ The ``importmap()`` function also outputs a set of "preloads":
 
 .. code-block:: html
 
-    <link rel="modulepreload" href="/assets/app-4e986c1a2318dd050b1d47db8d856278.js">
-    <link rel="modulepreload" href="/assets/duck-1b7a64b3b3d31219c262cf72521a5267.js">
+    <link rel="modulepreload" href="/assets/app-4e986c1a.js">
+    <link rel="modulepreload" href="/assets/duck-1b7a64b3.js">
 
 This is a performance optimization and you can learn more about below
 in :ref:`Performance: Add Preloading <performance-preloading>`.
@@ -454,10 +476,6 @@ from inside ``app.js``:
 Handling CSS
 ------------
 
-.. versionadded:: 6.4
-
-    The ability to import CSS files was introduced in Symfony 6.4.
-
 CSS can be added to your page by importing it from a JavaScript file. The default
 ``assets/app.js`` already imports ``assets/styles/app.css``:
 
@@ -532,9 +550,9 @@ for ``duck.png``:
 
 .. code-block:: css
 
-    /* public/assets/styles/app-3c16d9220694c0e56d8648f25e6035e9.css */
+    /* public/assets/styles/app-3c16d92m.css */
     .quack {
-        background-image: url('../images/duck-3c16d9220694c0e56d8648f25e6035e9.png');
+        background-image: url('../images/duck-3c16d92m.png');
     }
 
 .. _asset-mapper-tailwind:
@@ -611,7 +629,7 @@ Sometimes a JavaScript file you're importing (e.g. ``import './duck.js'``),
 or a CSS/image file you're referencing won't be found, and you'll see a 404
 error in your browser's console. You'll also notice that the 404 URL is missing
 the version hash in the filename (e.g. a 404 to ``/assets/duck.js`` instead of
-a path like ``/assets/duck.1b7a64b3b3d31219c262cf72521a5267.js``).
+a path like ``/assets/duck-1b7a64b3.js``).
 
 This is usually because the path is wrong. If you're referencing the file
 directly in a Twig template:
@@ -694,7 +712,9 @@ which will automatically do most of these things for you:
 - **Compress your assets**: Your web server should compress (e.g. using gzip)
   your assets (JavaScript, CSS, images) before sending them to the browser. This
   is automatically enabled in Caddy and can be activated in Nginx and Apache.
-  In Cloudflare, assets are compressed by default.
+  In Cloudflare, assets are compressed by default. AssetMapper also supports
+  :ref:`precompressing your web assets <performance-precompressing>` to further
+  improve performance.
 
 - **Set long-lived cache expiry**: Your web server should set a long-lived
   ``Cache-Control`` HTTP header on your assets. Because the AssetMapper component includes a version
@@ -710,10 +730,6 @@ check the performance of your site.
 Performance: Understanding Preloading
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.4
-
-    Automatic preloading of JavaScript files was introduced in Symfony 6.4.
-
 One issue that Lighthouse may report is:
 
     Avoid Chaining Critical Requests
@@ -746,10 +762,84 @@ even though it hasn't yet seen the ``import`` statement for them.
 Additionally, if the :doc:`WebLink Component </web_link>` is available in your application,
 Symfony will add a ``Link`` header in the response to preload the CSS files.
 
-.. versionadded:: 6.4
+.. _performance-precompressing:
+
+Pre-Compressing Assets
+----------------------
+
+.. versionadded:: 7.3
+
+    Support for pre-compressing assets was introduced in Symfony 7.3.
+
+Although most web servers (Caddy, Nginx, Apache, FrankenPHP) and services like Cloudflare
+provide asset compression features, AssetMapper also allows you to compress all
+your assets before serving them.
+
+This improves performance because you can compress assets using the highest (and
+slowest) compression ratios beforehand and provide those compressed assets to the
+server, which then returns them to the client without wasting CPU resources on
+compression.
+
+AssetMapper supports  `Brotli`_, `Zstandard`_ and  `gzip`_ compression formats.
+Before using any of them, the machine that pre-compresses assets must have
+installed the following PHP extensions or CLI commands:
+
+* Brotli: ``brotli`` CLI command; `brotli PHP extension`_;
+* Zstandard: ``zstd`` CLI command; `zstd PHP extension`_;
+* gzip: ``zopfli`` (better) or ``gzip`` CLI command; `zlib PHP extension`_.
 
-    Automatic preloading of CSS files when WebLink is available was
-    introduced in Symfony 6.4.
+Then, update your AssetMapper configuration to define which compression to use
+and which file extensions should be compressed:
+
+.. code-block:: yaml
+
+    # config/packages/asset_mapper.yaml
+    framework:
+        asset_mapper:
+            # ...
+
+            precompress:
+                # possible values: 'brotli', 'zstandard', 'gzip'
+                format: 'zstandard'
+
+                # you can also pass multiple values to generate files in several formats
+                # format: ['brotli', 'zstandard']
+
+                # if you don't define the following option, AssetMapper will compress all
+                # the extensions considered safe (css, js, json, svg, xml, ttf, otf, wasm, etc.)
+                extensions: ['css', 'js', 'json', 'svg', 'xml']
+
+Now, when running the ``asset-map:compile`` command, all matching files will be
+compressed in the configured format and at the highest compression level. The
+compressed files are created with the same name as the original but with the
+``.br``, ``.zst``, or ``.gz`` extension appended.
+
+Then, you need to configure your web server to serve the precompressed assets
+instead of the original ones:
+
+.. configuration-block::
+
+    .. code-block:: caddy
+
+        file_server {
+            precompressed br zstd gzip
+        }
+
+    .. code-block:: nginx
+
+        gzip_static on;
+
+        # Requires https://github.com/google/ngx_brotli
+        brotli_static on;
+
+        # Requires https://github.com/tokers/zstd-nginx-module
+        zstd_static on;
+
+.. tip::
+
+    AssetMapper provides an ``assets:compress`` CLI command and a service called
+    ``asset_mapper.compressor`` that you can use anywhere in your application to
+    compress any kind of files (e.g. files uploaded by users to your application).
 
 Frequently Asked Questions
 --------------------------
@@ -895,7 +985,7 @@ be versioned! It will output something like:
 
 .. code-block:: html+twig
 
-    <link rel="stylesheet" href="/assets/bundles/babdevpagerfanta/css/pagerfanta-ea64fc9c55f8394e696554f8aeb81a8e.css">
+    <link rel="stylesheet" href="/assets/bundles/babdevpagerfanta/css/pagerfanta-ea64fc9c.css">
 
 Overriding 3rd-Party Assets
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1015,10 +1105,6 @@ is useful if you want to avoid leaking sensitive files like ``.env`` or
 
 This option is enabled by default.
 
-.. versionadded:: 6.4
-
-    The ``exclude_dotfiles`` option was introduced in Symfony 6.4.
-
 .. _config-importmap-polyfill:
 
 ``framework.asset_mapper.importmap_polyfill``
@@ -1048,12 +1134,6 @@ via a CDN (i.e. the default value for this setting is ``es-module-shims``):
 
         $ php bin/console importmap:require es-module-shims
 
-.. versionadded:: 6.4
-
-    Passing an importmap name in ``importmap_polyfill`` was
-    introduced in Symfony 6.4. Prior to this, you could pass ``false``
-    or a custom URL to load the polyfill.
-
 ``framework.asset_mapper.importmap_script_attributes``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1230,10 +1310,6 @@ command as part of your CI to be warned anytime a new vulnerability is found.
     The command takes a ``--format`` option to choose the output format between
     ``txt`` and ``json``.
 
-.. versionadded:: 6.4
-
-    The ``importmap:audit`` command was introduced in Symfony 6.4.
-
 .. _latest asset-mapper recipe: https://github.com/symfony/recipes/tree/main/symfony/asset-mapper
 .. _import statement: https://caniuse.com/es6-module-dynamic-import
 .. _ES6: https://caniuse.com/es6
@@ -1261,3 +1337,9 @@ command as part of your CI to be warned anytime a new vulnerability is found.
 .. _strict-dynamic: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#strict-dynamic
 .. _kocal/biome-js-bundle: https://github.com/Kocal/BiomeJsBundle
 .. _`SensioLabs Minify Bundle`: https://github.com/sensiolabs/minify-bundle
+.. _`Brotli`: https://en.wikipedia.org/wiki/Brotli
+.. _`Zstandard`: https://en.wikipedia.org/wiki/Zstd
+.. _`gzip`: https://en.wikipedia.org/wiki/Gzip
+.. _`brotli PHP extension`: https://pecl.php.net/package/brotli
+.. _`zstd PHP extension`: https://pecl.php.net/package/zstd
+.. _`zlib PHP extension`: https://www.php.net/manual/en/book.zlib.php
diff --git a/html_sanitizer.rst b/html_sanitizer.rst
index 920d37a81c3..38d7664ccf7 100644
--- a/html_sanitizer.rst
+++ b/html_sanitizer.rst
@@ -1,10 +1,6 @@
 HTML Sanitizer
 ==============
 
-.. versionadded:: 6.1
-
-    The HTML Sanitizer component was introduced in Symfony 6.1.
-
 The HTML Sanitizer component aims at sanitizing/cleaning untrusted HTML
 code (e.g. created by a WYSIWYG editor in the browser) into HTML that can
 be trusted. It is based on the `HTML Sanitizer W3C Standard Proposal`_.
@@ -1023,11 +1019,6 @@ increase or decrease this limit:
 It is possible to disable this length limit by setting the max input length to
 ``-1``. Beware that it may expose your application to `DoS attacks`_.
 
-.. versionadded:: 6.4
-
-    The support for disabling the length limit of the HTML sanitizer was
-    introduced in Symfony 6.4.
-
 Custom Attribute Sanitizers
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/http_cache.rst b/http_cache.rst
index 7e886b022d0..1797219c649 100644
--- a/http_cache.rst
+++ b/http_cache.rst
@@ -229,10 +229,6 @@ The *easiest* way to cache a response is by caching it for a specific amount of
             return $response;
         }
 
-.. versionadded:: 6.2
-
-    The ``#[Cache]`` attribute was introduced in Symfony 6.2.
-
 Thanks to this new code, your HTTP response will have the following header:
 
 .. code-block:: text
diff --git a/http_cache/esi.rst b/http_cache/esi.rst
index 044430edcc3..588cad424cd 100644
--- a/http_cache/esi.rst
+++ b/http_cache/esi.rst
@@ -279,8 +279,4 @@ The ``render_esi`` helper supports three other useful options:
 ``absolute_uri``
      If set to true, an absolute URI will be generated. **default**: ``false``
 
-.. versionadded:: 6.2
-
-    The ``absolute_uri`` option was introduced in Symfony 6.2.
-
 .. _`ESI`: https://www.w3.org/TR/esi-lang/
diff --git a/http_cache/varnish.rst b/http_cache/varnish.rst
index a9bb668c100..6fcb7fd766b 100644
--- a/http_cache/varnish.rst
+++ b/http_cache/varnish.rst
@@ -62,7 +62,7 @@ If you know for sure that the backend never uses sessions or basic
 authentication, have Varnish remove the corresponding header from requests to
 prevent clients from bypassing the cache. In practice, you will need sessions
 at least for some parts of the site, e.g. when using forms with
-:doc:`CSRF Protection </security/csrf>`. In this situation, make sure to
+:doc:`stateful CSRF Protection </security/csrf>`. In this situation, make sure to
 :ref:`only start a session when actually needed <session-avoid-start>`
 and clear the session when it is no longer needed. Alternatively, you can look
 into :ref:`caching pages that contain CSRF protected forms <caching-pages-that-contain-csrf-protected-forms>`.
diff --git a/http_client.rst b/http_client.rst
index bdc843a32e8..a1c8f09bc1d 100644
--- a/http_client.rst
+++ b/http_client.rst
@@ -150,10 +150,18 @@ brings most of the available options with type-hinted getters and setters::
     $this->client = $client->withOptions(
         (new HttpOptions())
             ->setBaseUri('https://...')
+            // replaces *all* headers at once, and deletes the headers you do not provide
             ->setHeaders(['header-name' => 'header-value'])
+            // set or replace a single header using setHeader()
+            ->setHeader('another-header-name', 'another-header-value')
             ->toArray()
     );
 
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\HttpClient\\HttpOptions::setHeader`
+    method was introduced in Symfony 7.1.
+
 Some options are described in this guide:
 
 * `Authentication`_
@@ -640,13 +648,6 @@ of the opened file, but you can configure both with the PHP streaming configurat
     stream_context_set_option($fileHandle, 'http', 'filename', 'the-name.txt');
     stream_context_set_option($fileHandle, 'http', 'content_type', 'my/content-type');
 
-.. versionadded:: 6.3
-
-    The feature to upload files using handles was introduced in Symfony 6.3.
-    In previous Symfony versions you had to encode the body contents according
-    to the ``multipart/form-data`` content-type using the :doc:`Symfony Mime </components/mime>`
-    component.
-
 .. tip::
 
     When using multidimensional arrays the :class:`Symfony\\Component\\Mime\\Part\\Multipart\\FormDataPart`
@@ -753,10 +754,6 @@ when using any HTTP method and ``500``, ``504``, ``507`` and ``510`` when using
 an HTTP `idempotent method`_. Use the ``max_retries`` setting to configure the
 amount of times a request is retried.
 
-.. versionadded:: 6.4
-
-    The ``max_retries`` options was introduced in Symfony 6.4.
-
 Check out the full list of configurable :ref:`retry_failed options <reference-http-client-retry-failed>`
 to learn how to tweak each of them to fit your application needs.
 
@@ -776,10 +773,6 @@ each retry.
 Retry Over Several Base URIs
 ............................
 
-.. versionadded:: 6.3
-
-    The multiple ``base_uri`` feature was added in Symfony 6.3.
-
 The ``RetryableHttpClient`` can be configured to use multiple base URIs. This
 feature provides increased flexibility and reliability for making HTTP
 requests. Pass an array of base URIs as option ``base_uri`` when making a
@@ -998,11 +991,6 @@ If you want to define your own logic to handle variables of URI templates, you
 can do so by redefining the ``http_client.uri_template_expander`` alias. Your
 service must be invokable.
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\HttpClient\\UriTemplateHttpClient` was
-    introduced in Symfony 6.3.
-
 Performance
 -----------
 
@@ -1522,6 +1510,114 @@ installed in your application::
 :class:`Symfony\\Component\\HttpClient\\CachingHttpClient` accepts a third argument
 to set the options of the :class:`Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache`.
 
+Limit the Number of Requests
+----------------------------
+
+This component provides a :class:`Symfony\\Component\\HttpClient\\ThrottlingHttpClient`
+decorator that allows to limit the number of requests within a certain period,
+potentially delaying calls based on the rate limiting policy.
+
+The implementation leverages the
+:class:`Symfony\\Component\\RateLimiter\\LimiterInterface` class under the hood
+so the :doc:`Rate Limiter component </rate_limiter>` needs to be
+installed in your application::
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/framework.yaml
+        framework:
+            http_client:
+                scoped_clients:
+                    example.client:
+                        base_uri: 'https://example.com'
+                        rate_limiter: 'http_example_limiter'
+
+            rate_limiter:
+                # Don't send more than 10 requests in 5 seconds
+                http_example_limiter:
+                    policy: 'token_bucket'
+                    limit: 10
+                    rate: { interval: '5 seconds', amount: 10 }
+
+    .. code-block:: xml
+
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:http-client>
+                    <framework:scoped-client name="example.client"
+                        base-uri="https://example.com"
+                        rate-limiter="http_example_limiter"
+                    />
+                </framework:http-client>
+
+                <framework:rate-limiter>
+                    <!-- Don't send more than 10 requests in 5 seconds -->
+                    <framework:limiter name="http_example_limiter"
+                        policy="token_bucket"
+                        limit="10"
+                    >
+                        <framework:rate interval="5 seconds" amount="10"/>
+                    </framework:limiter>
+                </framework:rate-limiter>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->httpClient()->scopedClient('example.client')
+                ->baseUri('https://example.com')
+                ->rateLimiter('http_example_limiter');
+                // ...
+            ;
+
+            $framework->rateLimiter()
+                // Don't send more than 10 requests in 5 seconds
+                ->limiter('http_example_limiter')
+                    ->policy('token_bucket')
+                    ->limit(10)
+                    ->rate()
+                        ->interval('5 seconds')
+                        ->amount(10)
+                ;
+        };
+
+    .. code-block:: php-standalone
+
+        use Symfony\Component\HttpClient\HttpClient;
+        use Symfony\Component\HttpClient\ThrottlingHttpClient;
+        use Symfony\Component\RateLimiter\RateLimiterFactory;
+        use Symfony\Component\RateLimiter\Storage\InMemoryStorage;
+
+        $factory = new RateLimiterFactory([
+            'id' => 'http_example_limiter',
+            'policy' => 'token_bucket',
+            'limit' => 10,
+            'rate' => ['interval' => '5 seconds', 'amount' => 10],
+        ], new InMemoryStorage());
+        $limiter = $factory->create();
+
+        $client = HttpClient::createForBaseUri('https://example.com');
+        $throttlingClient = new ThrottlingHttpClient($client, $limiter);
+
+.. versionadded:: 7.1
+
+    The :class:`Symfony\\Component\\HttpClient\\ThrottlingHttpClient` was
+    introduced in Symfony 7.1.
+
 Consuming Server-Sent Events
 ----------------------------
 
@@ -1576,10 +1672,6 @@ to wrap your HTTP client, open a connection to a server that responds with a
     use the :method:`Symfony\\Component\\HttpClient\\Chunk\\ServerSentEvent::getArrayData`
     method to directly get the decoded JSON as array.
 
-.. versionadded:: 6.3
-
-    The ``ServerSentEvent::getArrayData()`` method was introduced in Symfony 6.3.
-
 Interoperability
 ----------------
 
@@ -1697,10 +1789,6 @@ You can also pass a set of default options to your client thanks to the
 
     // ...
 
-.. versionadded:: 6.2
-
-    The ``Psr18Client::withOptions()`` method was introduced in Symfony 6.2.
-
 HTTPlug
 ~~~~~~~
 
@@ -1802,10 +1890,6 @@ You can also pass a set of default options to your client thanks to the
 
     // ...
 
-.. versionadded:: 6.2
-
-    The ``HttplugClient::withOptions()`` method was introduced in Symfony 6.2.
-
 Native PHP Streams
 ~~~~~~~~~~~~~~~~~~
 
@@ -1973,6 +2057,20 @@ in order when requests are made::
     $response1 = $client->request('...'); // returns $responses[0]
     $response2 = $client->request('...'); // returns $responses[1]
 
+It is also possible to create a
+:class:`Symfony\\Component\\HttpClient\\Response\\MockResponse` directly
+from a file, which is particularly useful when storing your response
+snapshots in files::
+
+    use Symfony\Component\HttpClient\Response\MockResponse;
+
+    $response = MockResponse::fromFile('tests/fixtures/response.xml');
+
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\HttpClient\\Response\\MockResponse::fromFile`
+    method was introduced in Symfony 7.1.
+
 Another way of using :class:`Symfony\\Component\\HttpClient\\MockHttpClient` is to
 pass a callback that generates the responses dynamically when it's called::
 
@@ -2147,9 +2245,18 @@ You can use :class:`Symfony\\Component\\HttpClient\\Response\\JsonMockResponse`
         'foo' => 'bar',
     ]);
 
-.. versionadded:: 6.3
+Just like :class:`Symfony\\Component\\HttpClient\\Response\\MockResponse`, you can
+also create a :class:`Symfony\\Component\\HttpClient\\Response\\JsonMockResponse`
+directly from a file::
+
+    use Symfony\Component\HttpClient\Response\JsonMockResponse;
+
+    $response = JsonMockResponse::fromFile('tests/fixtures/response.json');
 
-    The ``JsonMockResponse`` was introduced in Symfony 6.3.
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\HttpClient\\Response\\JsonMockResponse::fromFile`
+    method was introduced in Symfony 7.1.
 
 Testing Request Data
 ~~~~~~~~~~~~~~~~~~~~
@@ -2302,10 +2409,6 @@ will find the associated response based on the request method, URL and body (if
 Note that **this won't work** if the request body or URI is random / always
 changing (e.g. if it contains current date or random UUIDs).
 
-.. versionadded:: 6.4
-
-    The ``HarFileResponseFactory`` was introduced in Symfony 6.4.
-
 Testing Network Transport Exceptions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2377,12 +2480,6 @@ body::
         }
     }
 
-.. versionadded:: 6.1
-
-    Being allowed to pass an exception directly to the body of a
-    :class:`Symfony\\Component\\HttpClient\\Response\\MockResponse` was
-    introduced in Symfony 6.1.
-
 .. _`cURL PHP extension`: https://www.php.net/curl
 .. _`Zlib PHP extension`: https://www.php.net/zlib
 .. _`PSR-17`: https://www.php-fig.org/psr/psr-17/
diff --git a/introduction/from_flat_php_to_symfony.rst b/introduction/from_flat_php_to_symfony.rst
index 7386f629546..3ae6a16d8a3 100644
--- a/introduction/from_flat_php_to_symfony.rst
+++ b/introduction/from_flat_php_to_symfony.rst
@@ -240,7 +240,7 @@ the ``templates/layout.php``:
 You now have a setup that will allow you to reuse the layout.
 Unfortunately, to accomplish this, you're forced to use a few ugly
 PHP functions (``ob_start()``, ``ob_get_clean()``) in the template. Symfony
-solves this using a `Templating`_ component. You'll see it in action shortly.
+solves this using `Twig`_. You'll see it in action shortly.
 
 Adding a Blog "show" Page
 -------------------------
@@ -568,9 +568,8 @@ nice way to group related pages. The controller functions are also sometimes cal
 
 The two controllers (or actions) are still lightweight. Each uses the
 :doc:`Doctrine ORM library </doctrine>` to retrieve objects from the
-database and the Templating component to render a template and return a
-``Response`` object. The ``list.html.twig`` template is now quite a bit simpler,
-and uses Twig:
+database and Twig to render a template and return a ``Response`` object.
+The ``list.html.twig`` template is now quite a bit simpler, and uses Twig:
 
 .. code-block:: html+twig
 
@@ -677,7 +676,7 @@ migrating the blog from flat PHP to Symfony has improved your life:
   :doc:`routing </routing>`, or rendering :doc:`controllers </controller>`;
 
 * Symfony gives you **access to open source tools** such as `Doctrine`_ and the
-  `Templating`_, :doc:`Security </security>`, :doc:`Form </components/form>`,
+  `Twig`_, :doc:`Security </security>`, :doc:`Form </components/form>`,
   `Validator`_ and `Translation`_ components (to name a few);
 
 * The application now enjoys **fully-flexible URLs** thanks to the Routing
@@ -694,7 +693,7 @@ A good selection of `Symfony community tools`_ can be found on GitHub.
 
 .. _`Model-View-Controller`: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
 .. _`Doctrine`: https://www.doctrine-project.org/
-.. _Templating: https://github.com/symfony/templating
+.. _Twig: https://github.com/twigphp/twig
 .. _Translation: https://github.com/symfony/translation
 .. _`Composer`: https://getcomposer.org
 .. _`download Composer`: https://getcomposer.org/download/
diff --git a/lock.rst b/lock.rst
index 400a918f7f3..3b9f1692df4 100644
--- a/lock.rst
+++ b/lock.rst
@@ -62,6 +62,8 @@ this behavior by using the ``lock`` key like:
             lock: 'oci:host=127.0.0.1;dbname=app'
             lock: 'mongodb://127.0.0.1/app?collection=lock'
             lock: '%env(LOCK_DSN)%'
+            # using an existing service
+            lock: 'snc_redis.default'
 
             # named locks
             lock:
@@ -119,6 +121,9 @@ this behavior by using the ``lock`` key like:
 
                     <framework:resource>%env(LOCK_DSN)%</framework:resource>
 
+                    <!-- using an existing service -->
+                    <framework:resource>snc_redis.default</framework:resource>
+
                     <!-- named locks -->
                     <framework:resource name="invoice">semaphore</framework:resource>
                     <framework:resource name="invoice">redis://r2.docker</framework:resource>
@@ -131,6 +136,7 @@ this behavior by using the ``lock`` key like:
 
         // config/packages/lock.php
         use Symfony\Config\FrameworkConfig;
+        use function Symfony\Component\DependencyInjection\Loader\Configurator\env;
 
         return static function (FrameworkConfig $framework): void {
             $framework->lock()
@@ -152,6 +158,8 @@ this behavior by using the ``lock`` key like:
                 ->resource('default', ['oci:host=127.0.0.1;dbname=app'])
                 ->resource('default', ['mongodb://127.0.0.1/app?collection=lock'])
                 ->resource('default', [env('LOCK_DSN')])
+                // using an existing service
+                ->resource('default', ['snc_redis.default'])
 
                 // named locks
                 ->resource('invoice', ['semaphore', 'redis://r2.docker'])
@@ -159,10 +167,9 @@ this behavior by using the ``lock`` key like:
             ;
         };
 
-.. versionadded:: 6.1
+.. versionadded:: 7.2
 
-    The CSV support (e.g. ``zookeeper://localhost01,localhost02:2181``) in
-    ZookeeperStore DSN was introduced in Symfony 6.1.
+    The option to use an existing service as the lock/semaphore was introduced in Symfony 7.2.
 
 Locking a Resource
 ------------------
diff --git a/logging/handlers.rst b/logging/handlers.rst
index c28bcfcd2cb..eb2b1ac2c9c 100644
--- a/logging/handlers.rst
+++ b/logging/handlers.rst
@@ -24,7 +24,7 @@ To use it, declare it as a service:
                     $endpoint: "http://127.0.0.1:9200"
                     $index: "monolog"
                     $client: null
-                    $level: !php/const Monolog\Logger::DEBUG
+                    $level: !php/enum Monolog\Level::Debug
                     $bubble: true
                     $elasticsearchVersion: '1.0.0'
 
@@ -48,7 +48,7 @@ To use it, declare it as a service:
                     <argument key="endpoint">http://127.0.0.1:9200</argument>
                     <argument key="index">monolog</argument>
                     <argument key="client"/>
-                    <argument key="level" type="constant">Monolog\Logger::DEBUG</argument>
+                    <argument key="level" type="enum">Monolog\Level::Debug</argument>
                     <argument key="bubble">true</argument>
                     <argument key="elasticsearchVersion">1.0.0</argument>
                 </service>
@@ -58,7 +58,7 @@ To use it, declare it as a service:
     .. code-block:: php
 
         // config/services.php
-        use Monolog\Logger;
+        use Monolog\Level;
         use Symfony\Bridge\Monolog\Handler\ElasticsearchLogstashHandler;
 
         $container->register(ElasticsearchLogstashHandler::class);
@@ -69,7 +69,7 @@ To use it, declare it as a service:
                 '$endpoint' => "http://127.0.0.1:9200",
                 '$index' => "monolog",
                 '$client' => null,
-                '$level' => Logger::DEBUG,
+                '$level' => Level::Debug,
                 '$bubble' => true,
                 '$elasticsearchVersion' => '1.0.0',
             ])
diff --git a/logging/monolog_console.rst b/logging/monolog_console.rst
index 0502c87dacf..4d007abe854 100644
--- a/logging/monolog_console.rst
+++ b/logging/monolog_console.rst
@@ -10,10 +10,9 @@ When a lot of logging has to happen, it's cumbersome to print information
 depending on the verbosity settings (``-v``, ``-vv``, ``-vvv``) because the
 calls need to be wrapped in conditions. For example::
 
-    use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
 
-    protected function execute(InputInterface $input, OutputInterface $output): int
+    public function __invoke(OutputInterface $output): int
     {
         if ($output->isDebug()) {
             $output->writeln('Some info');
@@ -34,28 +33,27 @@ the current log level and the console verbosity.
 
 The example above could then be rewritten as::
 
-    // src/Command/YourCommand.php
+    // src/Command/MyCommand.php
     namespace App\Command;
 
     use Psr\Log\LoggerInterface;
+    use Symfony\Component\Console\Attribute\AsCommand;
     use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
 
-    class YourCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
         public function __construct(
             private LoggerInterface $logger,
         ) {
-            parent::__construct();
         }
 
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(): int
         {
             $this->logger->debug('Some info');
             $this->logger->notice('Some more info');
 
-            // ...
+            return Command::SUCCESS;
         }
     }
 
diff --git a/mailer.rst b/mailer.rst
index 303c7db2061..bdc50757cdd 100644
--- a/mailer.rst
+++ b/mailer.rst
@@ -100,33 +100,37 @@ via a third-party provider:
 ===================== =============================================== ===============
 Service               Install with                                    Webhook support
 ===================== =============================================== ===============
+`AhaSend`_            ``composer require symfony/aha-send-mailer``    yes
 `Amazon SES`_         ``composer require symfony/amazon-mailer``
+`Azure`_              ``composer require symfony/azure-mailer``
 `Brevo`_              ``composer require symfony/brevo-mailer``       yes
 `Infobip`_            ``composer require symfony/infobip-mailer``
 `Mailgun`_            ``composer require symfony/mailgun-mailer``     yes
 `Mailjet`_            ``composer require symfony/mailjet-mailer``     yes
+`Mailomat`_           ``composer require symfony/mailomat-mailer``    yes
 `MailPace`_           ``composer require symfony/mail-pace-mailer``
-`MailerSend`_         ``composer require symfony/mailer-send-mailer``
-`Mandrill`_           ``composer require symfony/mailchimp-mailer``
+`MailerSend`_         ``composer require symfony/mailer-send-mailer`` yes
+`Mailtrap`_           ``composer require symfony/mailtrap-mailer``    yes
+`Mandrill`_           ``composer require symfony/mailchimp-mailer``   yes
+`Postal`_             ``composer require symfony/postal-mailer``
 `Postmark`_           ``composer require symfony/postmark-mailer``    yes
+`Resend`_             ``composer require symfony/resend-mailer``      yes
 `Scaleway`_           ``composer require symfony/scaleway-mailer``
 `SendGrid`_           ``composer require symfony/sendgrid-mailer``    yes
+`Sweego`_             ``composer require symfony/sweego-mailer``      yes
 ===================== =============================================== ===============
 
-.. versionadded:: 6.2
+.. versionadded:: 7.1
 
-    The Infobip integration was introduced in Symfony 6.2 and the ``MailPace``
-    integration was renamed in Symfony 6.2 (in previous Symfony versions it was
-    called ``OhMySMTP``).
+    The Azure and Resend integrations were introduced in Symfony 7.1.
 
-.. versionadded:: 6.3
+.. versionadded:: 7.2
 
-    The MailerSend integration was introduced in Symfony 6.3.
+    The Mailomat, Mailtrap, Postal and Sweego integrations were introduced in Symfony 7.2.
 
-.. versionadded:: 6.4
+.. versionadded:: 7.3
 
-    The ``Brevo`` (in previous Symfony versions it was called ``Sendinblue``)
-    and ``Scaleway`` integrations were introduced in Symfony 6.4.
+    The AhaSend integration was introduced in Symfony 7.3.
 
 .. note::
 
@@ -176,10 +180,16 @@ party provider:
 +------------------------+---------------------------------------------------------+
 | Provider               | Formats                                                 |
 +========================+=========================================================+
+| `AhaSend`_             | - API ``ahasend+api://KEY@default``                     |
+|                        | - HTTP n/a                                              |
+|                        | - SMTP ``ahasend+smtp://USERNAME:PASSWORD@default``     |
++------------------------+---------------------------------------------------------+
 | `Amazon SES`_          | - SMTP ``ses+smtp://USERNAME:PASSWORD@default``         |
 |                        | - HTTP ``ses+https://ACCESS_KEY:SECRET_KEY@default``    |
 |                        | - API ``ses+api://ACCESS_KEY:SECRET_KEY@default``       |
 +------------------------+---------------------------------------------------------+
+| `Azure`_               | - API ``azure+api://ACS_RESOURCE_NAME:KEY@default``     |
++------------------------+---------------------------------------------------------+
 | `Brevo`_               | - SMTP ``brevo+smtp://USERNAME:PASSWORD@default``       |
 |                        | - HTTP n/a                                              |
 |                        | - API ``brevo+api://KEY@default``                       |
@@ -208,14 +218,30 @@ party provider:
 |                        | - HTTP n/a                                              |
 |                        | - API ``mailjet+api://ACCESS_KEY:SECRET_KEY@default``   |
 +------------------------+---------------------------------------------------------+
+| `Mailomat`_            | - SMTP ``mailomat+smtp://USERNAME:PASSWORD@default``    |
+|                        | - HTTP n/a                                              |
+|                        | - API ``mailomat+api://KEY@default``                    |
++------------------------+---------------------------------------------------------+
 | `MailPace`_            | - SMTP ``mailpace+api://API_TOKEN@default``             |
 |                        | - HTTP n/a                                              |
 |                        | - API ``mailpace+api://API_TOKEN@default``              |
 +------------------------+---------------------------------------------------------+
+| `Mailtrap`_            | - SMTP ``mailtrap+smtp://PASSWORD@default``             |
+|                        | - HTTP n/a                                              |
+|                        | - API ``mailtrap+api://API_TOKEN@default``              |
++------------------------+---------------------------------------------------------+
+| `Postal`_              | - SMTP n/a                                              |
+|                        | - HTTP n/a                                              |
+|                        | - API ``postal+api://API_KEY@BASE_URL``                 |
++------------------------+---------------------------------------------------------+
 | `Postmark`_            | - SMTP ``postmark+smtp://ID@default``                   |
 |                        | - HTTP n/a                                              |
 |                        | - API ``postmark+api://KEY@default``                    |
 +------------------------+---------------------------------------------------------+
+| `Resend`_              | - SMTP ``resend+smtp://resend:API_KEY@default``         |
+|                        | - HTTP n/a                                              |
+|                        | - API ``resend+api://API_KEY@default``                  |
++------------------------+---------------------------------------------------------+
 | `Scaleway`_            | - SMTP ``scaleway+smtp://PROJECT_ID:API_KEY@default``   |
 |                        | - HTTP n/a                                              |
 |                        | - API ``scaleway+api://PROJECT_ID:API_KEY@default``     |
@@ -224,10 +250,10 @@ party provider:
 |                        | - HTTP n/a                                              |
 |                        | - API ``sendgrid+api://KEY@default``                    |
 +------------------------+---------------------------------------------------------+
-
-.. versionadded:: 6.3
-
-    The ``sandbox`` option in ``Mailjet`` API was introduced in Symfony 6.3.
+| `Sweego`_              | - SMTP ``sweego+smtp://LOGIN:PASSWORD@HOST:PORT``       |
+|                        | - HTTP n/a                                              |
+|                        | - API ``sweego+api://API_KEY@default``                  |
++------------------------+---------------------------------------------------------+
 
 .. warning::
 
@@ -242,12 +268,6 @@ party provider:
     you need to add the ``ping_threshold`` parameter to your ``MAILER_DSN`` with
     a value lower than ``10``: ``ses+smtp://USERNAME:PASSWORD@default?ping_threshold=9``
 
-.. warning::
-
-    If you send custom headers when using the `Amazon SES`_ transport (to receive
-    them later via a webhook), make sure to use the ``ses+https`` provider because
-    it's the only one that supports them.
-
 .. note::
 
     When using SMTP, the default timeout for sending a message before throwing an
@@ -314,6 +334,17 @@ The failover-transport starts using the first transport and if it fails, it
 will retry the same delivery with the next transports until one of them succeeds
 (or until all of them fail).
 
+By default, delivery is retried 60 seconds after a failed attempt. You can adjust
+the retry period by setting the ``retry_period`` option in the DSN:
+
+.. code-block:: env
+
+    MAILER_DSN="failover(postmark+api://ID@default sendgrid+smtp://KEY@default)?retry_period=15"
+
+.. versionadded:: 7.3
+
+    The ``retry_period`` option was introduced in Symfony 7.3.
+
 Load Balancing
 ~~~~~~~~~~~~~~
 
@@ -334,6 +365,17 @@ As with the failover transport, round-robin retries deliveries until
 a transport succeeds (or all fail). In contrast to the failover transport,
 it *spreads* the load across all its transports.
 
+By default, delivery is retried 60 seconds after a failed attempt. You can adjust
+the retry period by setting the ``retry_period`` option in the DSN:
+
+.. code-block:: env
+
+    MAILER_DSN="roundrobin(postmark+api://ID@default sendgrid+smtp://KEY@default)?retry_period=15"
+
+.. versionadded:: 7.3
+
+    The ``retry_period`` option was introduced in Symfony 7.3.
+
 TLS Peer Verification
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -354,9 +396,72 @@ may be specified as SHA1 or MD5 hash::
 
     $dsn = 'smtp://user:pass@smtp.example.com?peer_fingerprint=6A1CF3B08D175A284C30BC10DE19162307C7286E';
 
-.. versionadded:: 6.4
+Disabling Automatic TLS
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 7.1
+
+    The option to disable automatic TLS was introduced in Symfony 7.1.
+
+By default, the Mailer component will use encryption when the OpenSSL extension
+is enabled and the SMTP server supports ``STARTTLS``. This behavior can be turned
+off by calling ``setAutoTls(false)`` on the ``EsmtpTransport`` instance, or by
+setting the ``auto_tls`` option to ``false`` in the DSN::
+
+    $dsn = 'smtp://user:pass@10.0.0.25?auto_tls=false';
+
+.. warning::
+
+    It's not recommended to disable TLS while connecting to an SMTP server over
+    the Internet, but it can be useful when both the application and the SMTP
+    server are in a secured network, where there is no need for additional encryption.
+
+.. note::
+
+    This setting only works when the ``smtp://`` protocol is used.
+
+Ensure TLS
+~~~~~~~~~~
+
+You may want to ensure that TLS is used (either directly or via ``STARTTLS``)
+when sending mail over SMTP, regardless of other options or SMTP server support.
+To require TLS, call ``setRequireTls(true)`` on the ``EsmtpTransport`` instance,
+or set the ``require_tls`` option to ``true`` in the DSN::
+
+    $dsn = 'smtp://user:pass@10.0.0.25?require_tls=true';
+
+When TLS is required, a :class:`Symfony\\Component\\Mailer\\Exception\\TransportException`
+is thrown if a TLS connection cannot be established during the initial communication
+with the SMTP server.
+
+.. note::
+
+    This setting only applies when using the ``smtp://`` protocol.
+
+.. versionadded:: 7.3
+
+    The ``require_tls`` option was introduced in Symfony 7.3.
+
+Binding to IPv4 or IPv6
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 7.3
+
+    The option to bind to IPv4, or IPv6, or a specific IP address was introduced in Symfony 7.3.
+
+By default, the underlying ``SocketStream`` will bind to IPv4 or IPv6 based on the
+available interfaces. You can enforce binding to a specific protocol or IP address
+by using the ``source_ip`` option. To bind to IPv4, use::
+
+    $dsn = 'smtp://smtp.example.com?source_ip=0.0.0.0';
+
+As per RFC2732, IPv6 addresses must be enclosed in square brackets. To bind to IPv6, use::
+
+    $dsn = 'smtp://smtp.example.com?source_ip=[::]';
+
+.. note::
 
-    The ``peer_fingerprint`` option was introduced in Symfony 6.4.
+    This option only works when using the ``smtp://`` protocol.
 
 Overriding default SMTP authenticators
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -383,11 +488,6 @@ This can be done from ``EsmtpTransport`` constructor or using the
     // Option 2: call a method to redefine the authenticators
     $transport->setAuthenticators([new XOAuth2Authenticator()]);
 
-.. versionadded:: 6.3
-
-    The ``$authenticators`` constructor parameter and the ``setAuthenticators()``
-    method were introduced in Symfony 6.3.
-
 Other Options
 ~~~~~~~~~~~~~
 
@@ -423,10 +523,6 @@ Other Options
 
         $dsn = 'smtps://smtp.example.com?max_per_second=2'
 
-    .. versionadded:: 6.2
-
-        The ``max_per_second`` option was introduced in Symfony 6.2.
-
 Custom Transport Factories
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -514,6 +610,10 @@ both strings or address objects::
         // email address as a simple string
         ->from('fabien@example.com')
 
+        // non-ASCII characters are supported both in the local part and the domain;
+        // if the SMTP server doesn't support this feature, you'll see an exception
+        ->from('jânë.dœ@ëxãmplę.com')
+
         // email address as an object
         ->from(new Address('fabien@example.com'))
 
@@ -534,6 +634,11 @@ both strings or address objects::
     :ref:`configure emails globally <mailer-configure-email-globally>` to set the
     same ``From`` email to all messages.
 
+.. versionadded:: 7.2
+
+    Support for non-ASCII email addresses (e.g. ``jânë.dœ@ëxãmplę.com``)
+    was introduced in Symfony 7.2.
+
 .. note::
 
     The local part of the address (what goes before the ``@``) can include UTF-8
@@ -639,12 +744,6 @@ the ``DataPart``::
         ->addPart(new DataPart(fopen('/path/to/documents/contract.doc', 'r')))
     ;
 
-.. deprecated:: 6.2
-
-    In Symfony versions previous to 6.2, the method ``attachPart()`` could be
-    used to add attachments. This method has been deprecated and replaced
-    with ``addPart()``.
-
 Embedding Images
 ~~~~~~~~~~~~~~~~
 
@@ -696,15 +795,6 @@ method to define a custom Content-ID for the image and use it as its ``cid`` ref
         ->html('... <img src="cid:footer-signature@my-app"> ...')
     ;
 
-.. versionadded:: 6.1
-
-    The support of embedded images as HTML backgrounds was introduced in Symfony
-    6.1.
-
-.. versionadded:: 6.3
-
-    The support of custom ``cid`` for embedded images was introduced in Symfony 6.3.
-
 .. _mailer-configure-email-globally:
 
 Configuring Emails Globally
@@ -904,11 +994,6 @@ for Twig templates::
         ])
     ;
 
-.. versionadded:: 6.4
-
-    The :method:`Symfony\\Bridge\\Twig\\Mime\\TemplatedEmail::locale` method
-    was introduced in Symfony 6.4.
-
 Then, create the template:
 
 .. code-block:: html+twig
@@ -1030,6 +1115,18 @@ the email contents:
     <h1>Welcome {{ email.toName }}!</h1>
     {# ... #}
 
+By default this will create an attachment using the file path as file name:
+``Content-Disposition: inline; name="cid..."; filename="@images/logo.png"``.
+This behavior can be overridden by passing a custom file name as the third argument:
+
+.. code-block:: html+twig
+
+    <img src="{{ email.image('@images/logo.png', 'image/png', 'logo-acme.png') }}" alt="ACME Logo">
+
+.. versionadded:: 7.3
+
+    The third argument of ``email.image()`` was introduced in Symfony 7.3.
+
 .. _mailer-inline-css:
 
 Inlining CSS Styles
@@ -1327,6 +1424,81 @@ key but not a certificate::
         ->toArray()
     );
 
+Signing Messages Globally
+.........................
+
+Instead of creating a signer instance for each email, you can configure a global
+signer that automatically applies to all outgoing messages. This approach
+minimizes repetition and centralizes your configuration for DKIM and S/MIME signing.
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/mailer.yaml
+        framework:
+            mailer:
+                dkim_signer:
+                    key: 'file://%kernel.project_dir%/var/certificates/dkim.pem'
+                    domain: 'symfony.com'
+                    select: 's1'
+                smime_signer:
+                    key: '%kernel.project_dir%/var/certificates/smime.key'
+                    certificate: '%kernel.project_dir%/var/certificates/smime.crt'
+                    passphrase: ''
+
+    .. code-block:: xml
+
+        <!-- config/packages/mailer.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <!-- ... -->
+            <framework:config>
+                <framework:mailer>
+                    <framework:dkim-signer>
+                        <framework:key>file://%kernel.project_dir%/var/certificates/dkim.pem</framework:key>
+                        <framework:domain>symfony.com</framework:domain>
+                        <framework:select>s1</framework:select>
+                    </framework:dkim-signer>
+                    <framework:smime-signer>
+                        <framework:key>%kernel.project_dir%/var/certificates/smime.pem</framework:key>
+                        <framework:certificate>%kernel.project_dir%/var/certificates/smime.crt</framework:certificate>
+                        <framework:passphrase></framework:passphrase>
+                    </framework:smime-signer>
+                </framework:mailer>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/mailer.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $mailer = $framework->mailer();
+            $mailer->dsn('%env(MAILER_DSN)%');
+            $mailer->dkimSigner()
+                    ->key('file://%kernel.project_dir%/var/certificates/dkim.pem')
+                    ->domain('symfony.com')
+                    ->select('s1');
+
+            $mailer->smimeSigner()
+                    ->key('%kernel.project_dir%/var/certificates/smime.key')
+                    ->certificate('%kernel.project_dir%/var/certificates/smime.crt')
+                    ->passphrase('')
+            ;
+        };
+
+.. versionadded:: 7.3
+
+    Global message signing was introduced in Symfony 7.3.
+
 Encrypting Messages
 ~~~~~~~~~~~~~~~~~~~
 
@@ -1368,6 +1540,86 @@ and it will select the appropriate certificate depending on the ``To`` option::
     $firstEncryptedEmail = $encrypter->encrypt($firstEmail);
     $secondEncryptedEmail = $encrypter->encrypt($secondEmail);
 
+Encrypting Messages Globally
+............................
+
+Instead of creating a new encrypter for each email, you can configure a global S/MIME
+encrypter that automatically applies to all outgoing messages:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/mailer.yaml
+        framework:
+            mailer:
+                smime_encrypter:
+                    repository: App\Security\LocalFileCertificateRepository
+
+    .. code-block:: xml
+
+        <!-- config/packages/mailer.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <!-- ... -->
+            <framework:config>
+                <framework:mailer>
+                    <framework:smime-encrypter>
+                        <framework:repository>App\Security\LocalFileCertificateRepository</framework:repository>
+                    </framework:smime-encrypter>
+                </framework:mailer>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/mailer.php
+        use App\Security\LocalFileCertificateRepository;
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $mailer = $framework->mailer();
+            $mailer->smimeEncrypter()
+                    ->repository(LocalFileCertificateRepository::class)
+            ;
+        };
+
+The ``repository`` option is the ID of a service that implements
+:class:`Symfony\\Component\\Mailer\\EventListener\\SmimeCertificateRepositoryInterface`.
+This interface requires only one method: ``findCertificatePathFor()``, which must
+return the file path to the certificate associated with the given email address::
+
+    namespace App\Security;
+
+    use Symfony\Component\DependencyInjection\Attribute\Autowire;
+    use Symfony\Component\Mailer\EventListener\SmimeCertificateRepositoryInterface;
+
+    class LocalFileCertificateRepository implements SmimeCertificateRepositoryInterface
+    {
+        public function __construct(
+            #[Autowire(param: 'kernel.project_dir')]
+            private readonly string $projectDir
+        ){}
+
+        public function findCertificatePathFor(string $email): ?string
+        {
+            $hash = hash('sha256', strtolower(trim($email)));
+            $path = sprintf('%s/storage/%s.crt', $this->projectDir, $hash);
+
+            return file_exists($path) ? $path : null;
+        }
+    }
+
+.. versionadded:: 7.3
+
+    Global message encryption configuration was introduced in Symfony 7.3.
+
 .. _multiple-email-transports:
 
 Multiple Email Transports
@@ -1502,11 +1754,6 @@ the "rendering" of the email (computed headers, body rendering, ...) is also
 deferred and will only happen just before the email is sent by the Messenger
 handler.
 
-.. versionadded:: 6.2
-
-    The following example about rendering the email before calling
-    ``$mailer->send($email)`` works as of Symfony 6.2.
-
 When sending an email asynchronously, its instance must be serializable.
 This is always the case for :class:`Symfony\\Component\\Mailer\\Mailer`
 instances, but when sending a
@@ -1580,11 +1827,6 @@ disable asynchronous delivery.
     an open connection to the SMTP server in between sending emails.
     You can do so by using the ``stop()`` method.
 
-.. versionadded:: 6.1
-
-    The :method:`Symfony\\Component\\Mailer\\Transport\\Smtp\\SmtpTransport::stop`
-    method was made public in Symfony 6.1.
-
 You can also select the transport by adding an ``X-Bus-Transport`` header (which
 will be removed automatically from the final message)::
 
@@ -1592,10 +1834,6 @@ will be removed automatically from the final message)::
     $email->getHeaders()->addTextHeader('X-Bus-Transport', 'app.another_bus');
     $mailer->send($email);
 
-.. versionadded:: 6.2
-
-    The ``X-Bus-Transport`` header support was introduced in Symfony 6.2.
-
 Adding Tags and Metadata to Emails
 ----------------------------------
 
@@ -1624,6 +1862,7 @@ The following transports currently support tags and metadata:
 
 * Brevo
 * Mailgun
+* Mailtrap
 * Mandrill
 * Postmark
 * Sendgrid
@@ -1631,23 +1870,16 @@ The following transports currently support tags and metadata:
 The following transports only support tags:
 
 * MailPace
+* Resend
 
 The following transports only support metadata:
 
 * Amazon SES (note that Amazon refers to this feature as "tags", but Symfony
   calls it "metadata" because it contains a key and a value)
 
-.. versionadded:: 6.1
-
-    Metadata support for Amazon SES was introduced in Symfony 6.1.
-
 Draft Emails
 ------------
 
-.. versionadded:: 6.1
-
-    ``Symfony\Component\Mime\DraftEmail`` was introduced in 6.1.
-
 :class:`Symfony\\Component\\Mime\\DraftEmail` is a special instance of
 :class:`Symfony\\Component\\Mime\\Email`. Its purpose is to build up an email
 (with body, attachments, etc) and make available to download as an ``.eml`` with
@@ -1672,7 +1904,7 @@ Here's an example of making one available to download::
         {
             $message = (new DraftEmail())
                 ->html($this->renderView(/* ... */))
-                ->attach(/* ... */)
+                ->addPart(/* ... */)
             ;
 
             $response = new Response($message->toString());
@@ -1719,10 +1951,6 @@ the email is sent::
         $event->addStamp(new SomeMessengerStamp());
     }
 
-.. versionadded:: 6.2
-
-    Methods ``addStamp()`` and ``getStamps()`` were introduced in Symfony 6.2.
-
 If you want to stop the Message from being sent, call ``reject()`` (it will
 also stop the event propagation)::
 
@@ -1733,10 +1961,6 @@ also stop the event propagation)::
         $event->reject();
     }
 
-.. versionadded:: 6.3
-
-    The ``reject()`` method was introduced in Symfony 6.3.
-
 Execute this command to find out which listeners are registered for this event
 and their priorities:
 
@@ -1751,10 +1975,6 @@ SentMessageEvent
 
 **Event Class**: :class:`Symfony\\Component\\Mailer\\Event\\SentMessageEvent`
 
-.. versionadded:: 6.2
-
-    The ``SentMessageEvent`` event was introduced in Symfony 6.2.
-
 ``SentMessageEvent`` allows you to act on the :class:`Symfony\\Component\\\Mailer\\\SentMessage`
 class to access the original message (``getOriginalMessage()``) and some
 :ref:`debugging information <mailer-debugging-emails>` (``getDebug()``) such as
@@ -1784,10 +2004,6 @@ FailedMessageEvent
 
 **Event Class**: :class:`Symfony\\Component\\Mailer\\Event\\FailedMessageEvent`
 
-.. versionadded:: 6.2
-
-    The ``FailedMessageEvent`` event was introduced in Symfony 6.2.
-
 ``FailedMessageEvent`` allows acting on the initial message in case of a failure
 and some :ref:`debugging information <mailer-debugging-emails>` (``getDebug()``)
 such as the HTTP calls made by the HTTP transports, which is useful for debugging errors::
@@ -1843,10 +2059,6 @@ to test if sending emails works correctly:
 This command bypasses the :doc:`Messenger bus </messenger>`, if configured, to
 ease testing emails even when the Messenger consumer is not running.
 
-.. versionadded:: 6.2
-
-    The ``mailer:test`` command was introduced in Symfony 6.2.
-
 Disabling Delivery
 ~~~~~~~~~~~~~~~~~~
 
@@ -1949,6 +2161,75 @@ a specific address, instead of the *real* address:
             ;
         };
 
+Use the ``allowed_recipients`` option to define specific addresses that should
+still receive their original emails. These messages will also be sent to the
+address(es) defined in ``recipients``, as with all other emails:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/mailer.yaml
+        when@dev:
+            framework:
+                mailer:
+                    envelope:
+                        recipients: ['youremail@example.com']
+                        allowed_recipients:
+                            - 'internal@example.com'
+                            # you can also use regular expression to define allowed recipients
+                            - 'internal-.*@example.(com|fr)'
+
+    .. code-block:: xml
+
+        <!-- config/packages/mailer.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <!-- ... -->
+            <framework:config>
+                <framework:mailer>
+                    <framework:envelope>
+                        <framework:recipient>youremail@example.com</framework:recipient>
+                        <framework:allowed-recipient>internal@example.com</framework:allowed-recipient>
+                        <!-- you can also use regular expression to define allowed recipients -->
+                        <framework:allowed-recipient>internal-.*@example.(com|fr)</framework:allowed-recipient>
+                    </framework:envelope>
+                </framework:mailer>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/mailer.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            // ...
+            $framework->mailer()
+                ->envelope()
+                    ->recipients(['youremail@example.com'])
+                    ->allowedRecipients([
+                        'internal@example.com',
+                        // you can also use regular expression to define allowed recipients
+                        'internal-.*@example.(com|fr)',
+                    ])
+            ;
+        };
+
+With this configuration, all emails will be sent to ``youremail@example.com``.
+Additionally, emails sent to ``internal@example.com``, ``internal-monitoring@example.fr``,
+etc., will also be delivered to those addresses.
+
+.. versionadded:: 7.1
+
+    The ``allowed_recipients`` option was introduced in Symfony 7.1.
+
 Write a Functional Test
 ~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1987,7 +2268,9 @@ the :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait`::
    following the redirection and the message will be lost from the mailer event
    handler.
 
+.. _`AhaSend`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/AhaSend/README.md
 .. _`Amazon SES`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Amazon/README.md
+.. _`Azure`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Azure/README.md
 .. _`App Password`: https://support.google.com/accounts/answer/185833
 .. _`Brevo`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Brevo/README.md
 .. _`default_socket_timeout`: https://www.php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout
@@ -2004,11 +2287,16 @@ the :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\MailerAssertionsTrait`::
 .. _`Mailgun`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md
 .. _`Mailjet`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailjet/README.md
 .. _`Markdown syntax`: https://commonmark.org/
+.. _`Mailomat`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailomat/README.md
 .. _`MailPace`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/MailPace/README.md
 .. _`OpenSSL PHP extension`: https://www.php.net/manual/en/book.openssl.php
 .. _`PEM encoded`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail
+.. _`Postal`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Postal/README.md
 .. _`Postmark`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Postmark/README.md
+.. _`Mailtrap`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Mailtrap/README.md
+.. _`Resend`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Resend/README.md
 .. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt
 .. _`S/MIME`: https://en.wikipedia.org/wiki/S/MIME
 .. _`Scaleway`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Scaleway/README.md
 .. _`SendGrid`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md
+.. _`Sweego`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Mailer/Bridge/Sweego/README.md
diff --git a/messenger.rst b/messenger.rst
index f8597d78e33..9ffb4164426 100644
--- a/messenger.rst
+++ b/messenger.rst
@@ -71,10 +71,6 @@ message class (or a message interface)::
     methods. You may use the attribute on as many methods in a single class as you
     like, allowing you to group the handling of multiple related types of messages.
 
-.. versionadded:: 6.1
-
-    Support for ``#[AsMessageHandler]`` on methods was introduced in Symfony 6.1.
-
 Thanks to :ref:`autoconfiguration <services-autoconfigure>` and the ``SmsNotification``
 type-hint, Symfony knows that this handler should be called when an ``SmsNotification``
 message is dispatched. Most of the time, this is all you need to do. But you can
@@ -207,8 +203,23 @@ Routing Messages to a Transport
 Now that you have a transport configured, instead of handling a message immediately,
 you can configure them to be sent to a transport:
 
+.. _messenger-message-attribute:
+
 .. configuration-block::
 
+    .. code-block:: php-attributes
+
+        // src/Message/SmsNotification.php
+        namespace App\Message;
+
+        use Symfony\Component\Messenger\Attribute\AsMessage;
+
+        #[AsMessage('async')]
+        class SmsNotification
+        {
+            // ...
+        }
+
     .. code-block:: yaml
 
         # config/packages/messenger.yaml
@@ -255,15 +266,26 @@ you can configure them to be sent to a transport:
             ;
         };
 
+.. versionadded:: 7.2
+
+    The ``#[AsMessage]`` attribute was introduced in Symfony 7.2.
+
 Thanks to this, the ``App\Message\SmsNotification`` will be sent to the ``async``
 transport and its handler(s) will *not* be called immediately. Any messages not
 matched under ``routing`` will still be handled immediately, i.e. synchronously.
 
 .. note::
 
-    You may use a partial PHP namespace like ``'App\Message\*'`` to match all
-    the messages within the matching namespace. The only requirement is that the
-    ``'*'`` wildcard has to be placed at the end of the namespace.
+    If you configure routing with both YAML/XML/PHP configuration files and
+    PHP attributes, the configuration always takes precedence over the class
+    attribute. This behavior allows you to override routing on a per-environment basis.
+
+.. note::
+
+    When configuring the routing in separate YAML/XML/PHP files, you can use a partial
+    PHP namespace like ``'App\Message\*'`` to match all the messages within the
+    matching namespace. The only requirement is that the ``'*'`` wildcard has to
+    be placed at the end of the namespace.
 
     You may use ``'*'`` as the message class. This will act as a default routing
     rule for any message not matched under ``routing``. This is useful to ensure
@@ -279,6 +301,27 @@ to multiple transports:
 
 .. configuration-block::
 
+    .. code-block:: php-attributes
+
+        // src/Message/SmsNotification.php
+        namespace App\Message;
+
+        use Symfony\Component\Messenger\Attribute\AsMessage;
+
+        #[AsMessage(['async', 'audit'])]
+        class SmsNotification
+        {
+            // ...
+        }
+
+        // if you prefer, you can also apply multiple attributes to the message class
+        #[AsMessage('async')]
+        #[AsMessage('audit')]
+        class SmsNotification
+        {
+            // ...
+        }
+
     .. code-block:: yaml
 
         # config/packages/messenger.yaml
@@ -349,11 +392,6 @@ to multiple transports:
     name as its only argument. For more information about stamps, see
     `Envelopes & Stamps`_.
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Component\\Messenger\\Stamp\\TransportNamesStamp`
-    stamp was introduced in Symfony 6.2.
-
 Doctrine Entities in Messages
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -494,6 +532,35 @@ The first argument is the receiver's name (or service id if you routed to a
 custom service). By default, the command will run forever: looking for new messages
 on your transport and handling them. This command is called your "worker".
 
+If you want to consume messages from all available receivers, you can use the
+command with the ``--all`` option:
+
+.. code-block:: terminal
+
+    $ php bin/console messenger:consume --all
+
+.. versionadded:: 7.1
+
+    The ``--all`` option was introduced in Symfony 7.1.
+
+Messages that take a long time to process may be redelivered prematurely because
+some transports assume that an unacknowledged message is lost. To prevent this
+issue, use the ``--keepalive`` command option to specify an interval (in seconds;
+default value = ``5``) at which the message is marked as "in progress". This prevents
+the message from being redelivered until the worker completes processing it:
+
+.. code-block:: terminal
+
+    $ php bin/console messenger:consume --keepalive
+
+.. note::
+
+    This option is only available for the following transports: Beanstalkd, AmazonSQS, Doctrine and Redis.
+
+.. versionadded:: 7.2
+
+    The ``--keepalive`` option was introduced in Symfony 7.2.
+
 .. tip::
 
     In a development environment and if you're using the Symfony CLI tool,
@@ -686,15 +753,19 @@ of some or all transports:
     # shows stats only for some transports
     $ php bin/console messenger:stats my_transport_name other_transport_name
 
+    # you can also output the stats in JSON format
+    $ php bin/console messenger:stats --format=json
+    $ php bin/console messenger:stats my_transport_name other_transport_name --format=json
+
+.. versionadded:: 7.2
+
+    The ``format`` option was introduced in Symfony 7.2.
+
 .. note::
 
     In order for this command to work, the configured transport's receiver must implement
     :class:`Symfony\\Component\\Messenger\\Transport\\Receiver\\MessageCountAwareInterface`.
 
-.. versionadded:: 6.2
-
-    The ``messenger:stats`` command was introduced in Symfony 6.2.
-
 .. _messenger-supervisor:
 
 Supervisor Configuration
@@ -778,11 +849,56 @@ message before terminating.
 
 However, you might prefer to use different POSIX signals for graceful shutdown.
 You can override default ones by setting the ``framework.messenger.stop_worker_on_signals``
-configuration option.
+configuration option:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/messenger.yaml
+        framework:
+            messenger:
+                stop_worker_on_signals:
+                    - SIGTERM
+                    - SIGINT
+                    - SIGUSR1
+
+    .. code-block:: xml
+
+        <!-- config/packages/messenger.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                   xmlns:framework="http://symfony.com/schema/dic/symfony"
+                   xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:messenger>
+                    <!-- ... -->
+                    <framework:stop-worker-on-signal>SIGTERM</framework:stop-worker-on-signal>
+                    <framework:stop-worker-on-signal>SIGINT</framework:stop-worker-on-signal>
+                    <framework:stop-worker-on-signal>SIGUSR1</framework:stop-worker-on-signal>
+                </framework:messenger>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/messenger.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->messenger()
+                ->stopWorkerOnSignals(['SIGTERM', 'SIGINT', 'SIGUSR1']);
+        };
 
-.. versionadded:: 6.3
+.. versionadded:: 7.3
 
-    The ``framework.messenger.stop_worker_on_signals`` option was introduced in Symfony 6.3.
+    Support for signals plain names in configuration was introduced in Symfony 7.3.
+    Previously, you had to use the numeric values of signals as defined by the
+    ``pcntl`` extension's `predefined constants`_.
 
 In some cases the ``SIGTERM`` signal is sent by Supervisor itself (e.g. stopping
 a Docker container having Supervisor as its entrypoint). In these cases you
@@ -905,21 +1021,11 @@ properties in the ``reset()`` method.
 If you don't want to reset the container, add the ``--no-reset`` option when
 running the ``messenger:consume`` command.
 
-.. deprecated:: 6.1
-
-    In Symfony versions previous to 6.1, the service container didn't reset
-    automatically between messages and you had to set the
-    ``framework.messenger.reset_on_message`` option to ``true``.
-
 .. _messenger-retries-failures:
 
 Rate Limited Transport
 ~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.2
-
-    The ``rate_limiter`` option was introduced in Symfony 6.2.
-
 Sometimes you might need to rate limit your message worker. You can configure a
 rate limiter on a transport (requires the :doc:`RateLimiter component </rate_limiter>`)
 by setting its ``rate_limiter`` option:
@@ -1004,6 +1110,9 @@ this is configurable for each transport:
                             # e.g. 1 second delay, 2 seconds, 4 seconds
                             multiplier: 2
                             max_delay: 0
+                            # applies randomness to the delay that can prevent the thundering herd effect
+                            # the value (between 0 and 1.0) is the percentage of 'delay' that will be added/subtracted
+                            jitter: 0.1
                             # override all of this with a service that
                             # implements Symfony\Component\Messenger\Retry\RetryStrategyInterface
                             # service: null
@@ -1023,7 +1132,7 @@ this is configurable for each transport:
             <framework:config>
                 <framework:messenger>
                     <framework:transport name="async_priority_high" dsn="%env(MESSENGER_TRANSPORT_DSN)%?queue_name=high_priority">
-                        <framework:retry-strategy max-retries="3" delay="1000" multiplier="2" max-delay="0"/>
+                        <framework:retry-strategy max-retries="3" delay="1000" multiplier="2" max-delay="0" jitter="0.1"/>
                     </framework:transport>
                 </framework:messenger>
             </framework:config>
@@ -1048,12 +1157,19 @@ this is configurable for each transport:
                     // e.g. 1 second delay, 2 seconds, 4 seconds
                     ->multiplier(2)
                     ->maxDelay(0)
+                    // applies randomness to the delay that can prevent the thundering herd effect
+                    // the value (between 0 and 1.0) is the percentage of 'delay' that will be added/subtracted
+                    ->jitter(0.1)
                     // override all of this with a service that
                     // implements Symfony\Component\Messenger\Retry\RetryStrategyInterface
                     ->service(null)
             ;
         };
 
+.. versionadded:: 7.1
+
+    The ``jitter`` option was introduced in Symfony 7.1.
+
 .. tip::
 
     Symfony triggers a :class:`Symfony\\Component\\Messenger\\Event\\WorkerMessageRetriedEvent`
@@ -1065,10 +1181,6 @@ this is configurable for each transport:
     the serialized form of the message is saved, which prevents to serialize it
     again if the message is later retried.
 
-    .. versionadded:: 6.1
-
-        The ``SerializedMessageStamp`` class was introduced in Symfony 6.1.
-
 Avoiding Retrying
 ~~~~~~~~~~~~~~~~~
 
@@ -1077,6 +1189,12 @@ and should not be retried. If you throw
 :class:`Symfony\\Component\\Messenger\\Exception\\UnrecoverableMessageHandlingException`,
 the message will not be retried.
 
+.. note::
+
+    Messages that will not be retried, will still show up in the configured failure transport.
+    If you want to avoid that, consider handling the error yourself and let the handler
+    successfully end.
+
 Forcing Retrying
 ~~~~~~~~~~~~~~~~
 
@@ -1085,6 +1203,15 @@ and must be retried. If you throw
 :class:`Symfony\\Component\\Messenger\\Exception\\RecoverableMessageHandlingException`,
 the message will always be retried infinitely and ``max_retries`` setting will be ignored.
 
+You can define a custom retry delay (e.g., to use the value from the ``Retry-After``
+header in an HTTP response) by setting the ``retryDelay`` argument in the
+constructor of the ``RecoverableMessageHandlingException``.
+
+.. versionadded:: 7.2
+
+    The ``retryDelay`` argument and the ``getRetryDelay()`` method were introduced
+    in Symfony 7.2.
+
 .. _messenger-failure-transport:
 
 Saving & Retrying Failed Messages
@@ -1170,7 +1297,7 @@ to retry them:
     # see details about a specific failure
     $ php bin/console messenger:failed:show 20 -vv
 
-    # view and retry messages one-by-one
+    # for each message, this command asks whether to retry, skip, or delete
     $ php bin/console messenger:failed:retry -vv
 
     # retry specific messages
@@ -1185,18 +1312,23 @@ to retry them:
     # remove all messages in the failure transport
     $ php bin/console messenger:failed:remove --all
 
-.. versionadded:: 6.2
-
-    The ``--class-filter`` and ``--stats`` options were introduced in Symfony 6.2.
-
-.. versionadded:: 6.4
-
-    The ``--all`` option was introduced in Symfony 6.4.
+    # remove only App\Message\MyMessage messages
+    $ php bin/console messenger:failed:remove --class-filter='App\Message\MyMessage'
 
 If the message fails again, it will be re-sent back to the failure transport
 due to the normal :ref:`retry rules <messenger-retries-failures>`. Once the max
 retry has been hit, the message will be discarded permanently.
 
+.. versionadded:: 7.2
+
+    The option to skip a message in the ``messenger:failed:retry`` command was
+    introduced in Symfony 7.2
+
+.. versionadded:: 7.3
+
+    The option to filter by a message class in the ``messenger:failed:remove`` command was
+    introduced in Symfony 7.3
+
 Multiple Failed Transports
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1513,14 +1645,14 @@ The transport has a number of options:
     Exchange flags
 
 ``exchange[name]``
-    Name of the exchange
+    Name of the exchange. Use an empty string to use the default exchange.
 
 ``exchange[type]`` (default: ``fanout``)
     Type of exchange
 
-.. versionadded:: 6.1
+.. versionadded:: 7.3
 
-    The ``connection_name`` option was introduced in Symfony 6.1.
+    Empty string support for ``exchange[name]`` was introduced in Symfony 7.3.
 
 You can also configure AMQP-specific settings on your message by adding
 :class:`Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpStamp` to
@@ -1625,6 +1757,13 @@ in the table.
     The length of time to wait for a response when calling
     ``PDO::pgsqlGetNotify``, in milliseconds.
 
+The Doctrine transport supports the ``--keepalive`` option by periodically updating
+the ``delivered_at`` timestamp to prevent the message from being redelivered.
+
+.. versionadded:: 7.3
+
+    Keepalive support was introduced in Symfony 7.3.
+
 Beanstalkd Transport
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -1647,8 +1786,13 @@ The Beanstalkd transport DSN may looks like this:
 
 The transport has a number of options:
 
-``tube_name`` (default: ``default``)
-    Name of the queue
+``bury_on_reject`` (default: ``false``)
+    When set to ``true``, rejected messages are placed into a "buried" state
+    in Beanstalkd instead of being deleted.
+
+    .. versionadded:: 7.3
+
+        The ``bury_on_reject`` option was introduced in Symfony 7.3.
 
 ``timeout`` (default: ``0``)
     Message reservation timeout - in seconds. 0 will cause the server to
@@ -1658,6 +1802,33 @@ The transport has a number of options:
     The message time to run before it is put back in the ready queue - in
     seconds.
 
+``tube_name`` (default: ``default``)
+    Name of the queue
+
+The Beanstalkd transport supports the ``--keepalive`` option by using Beanstalkd's
+``touch`` command to periodically reset the job's ``ttr``.
+
+.. versionadded:: 7.2
+
+    Keepalive support was introduced in Symfony 7.2.
+
+The Beanstalkd transport lets you set the priority of the messages being dispatched.
+Use the :class:`Symfony\\Component\\Messenger\\Bridge\\Beanstalkd\\Transport\\BeanstalkdPriorityStamp`
+and pass a number to specify the priority (default = ``1024``; lower numbers mean higher priority)::
+
+    use App\Message\SomeMessage;
+    use Symfony\Component\Messenger\Stamp\BeanstalkdPriorityStamp;
+
+    $this->bus->dispatch(new SomeMessage('some data'), [
+        // 0 = highest priority
+        // 2**32 - 1 = lowest priority
+        new BeanstalkdPriorityStamp(0),
+    ]);
+
+.. versionadded:: 7.3
+
+    ``BeanstalkdPriorityStamp`` support was introduced in Symfony 7.3.
+
 .. _messenger-redis-transport:
 
 Redis Transport
@@ -1757,6 +1928,13 @@ under the transport in ``messenger.yaml``:
 ``sentinel_master`` (default: ``null``)
     String, if null or empty Sentinel support is disabled
 
+``redis_sentinel`` (default: ``null``)
+    An alias of the ``sentinel_master`` option
+
+    .. versionadded:: 7.1
+
+        The ``redis_sentinel`` option was introduced in Symfony 7.1.
+
 ``ssl`` (default: ``null``)
     Map of `SSL context options`_ for the TLS channel. This is useful for example
     to change the requirements for the TLS channel in tests:
@@ -1779,11 +1957,6 @@ under the transport in ``messenger.yaml``:
                                 verify_peer: true
                                 verify_peer_name: true
 
-.. versionadded:: 6.1
-
-    The ``persistent_id``, ``retry_interval``, ``read_timeout``, ``timeout``, and
-    ``sentinel_master`` options were introduced in Symfony 6.1.
-
 .. warning::
 
     There should never be more than one ``messenger:consume`` command running with the same
@@ -1802,6 +1975,13 @@ under the transport in ``messenger.yaml``:
     in your case) to avoid memory leaks. Otherwise, all messages will remain
     forever in Redis.
 
+The Redis transport supports the ``--keepalive`` option by using Redis's ``XCLAIM``
+command to periodically reset the message's idle time to zero.
+
+.. versionadded:: 7.3
+
+    Keepalive support was introduced in Symfony 7.3.
+
 In Memory Transport
 ~~~~~~~~~~~~~~~~~~~
 
@@ -1876,12 +2056,6 @@ during a request::
         }
     }
 
-.. versionadded:: 6.3
-
-    The namespace of the ``InMemoryTransport`` class changed in Symfony 6.3 from
-    ``Symfony\Component\Messenger\Transport\InMemoryTransport`` to
-    ``Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport``.
-
 The transport has a number of options:
 
 ``serialize`` (boolean, default: ``false``)
@@ -1950,6 +2124,12 @@ The transport has a number of options:
 ``queue_name`` (default: ``messages``)
     Name of the queue
 
+``queue_attributes``
+    Attributes of a queue as per `SQS CreateQueue API`_. Array of strings indexed by keys of ``AsyncAws\Sqs\Enum\QueueAttributeName``.
+
+``queue_tags``
+    Cost allocation tags of a queue as per `SQS CreateQueue API`_. Array of strings indexed by strings.
+
 ``region`` (default: ``eu-west-1``)
     Name of the AWS region
 
@@ -1965,9 +2145,9 @@ The transport has a number of options:
 ``wait_time`` (default: ``20``)
     `Long polling`_ duration in seconds
 
-.. versionadded:: 6.1
+.. versionadded:: 7.3
 
-    The ``session_token`` option was introduced in Symfony 6.1.
+    The ``queue_attributes`` and ``queue_tags`` options were introduced in Symfony 7.3.
 
 .. note::
 
@@ -1998,17 +2178,16 @@ The transport has a number of options:
     You can learn more about middlewares in
     :ref:`the dedicated section <messenger_middleware>`.
 
-    .. versionadded:: 6.4
-
-        The
-        :class:`Symfony\\Component\\Messenger\\Bridge\\AmazonSqs\\Middleware\\AddFifoStampMiddleware`,
-        :class:`Symfony\\Component\\Messenger\\Bridge\\AmazonSqs\\MessageDeduplicationAwareInterface`
-        and :class:`Symfony\\Component\\Messenger\\Bridge\\AmazonSqs\\MessageGroupAwareInterface`
-        were introduced in Symfony 6.4.
-
     FIFO queues don't support setting a delay per message, a value of ``delay: 0``
     is required in the retry strategy settings.
 
+The SQS transport supports the ``--keepalive`` option by using the ``ChangeMessageVisibility``
+action to periodically update the ``VisibilityTimeout`` of the message.
+
+.. versionadded:: 7.2
+
+    Keepalive support was introduced in Symfony 7.2.
+
 Serializing Messages
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -2092,6 +2271,22 @@ on a case-by-case basis via the :class:`Symfony\\Component\\Messenger\\Stamp\\Se
     provides that control. See `SymfonyCasts' message serializer tutorial`_ for
     details.
 
+Closing Connections
+~~~~~~~~~~~~~~~~~~~
+
+When using a transport that requires a connection, you can close it by calling the
+:method:`Symfony\\Component\\Messenger\\Transport\\CloseableTransportInterface::close`
+method to free up resources in long-running processes.
+
+This interface is implemented by the following transports: AmazonSqs, Amqp, and Redis.
+If you need to close a Doctrine connection, you can do so
+:ref:`using middleware <middleware-for-doctrine>`.
+
+.. versionadded:: 7.3
+
+    The ``CloseableTransportInterface`` and its ``close()`` method were introduced
+    in Symfony 7.3.
+
 Running Commands And External Processes
 ---------------------------------------
 
@@ -2133,12 +2328,6 @@ contains many useful information such as the exit code or the output of the
 process. You can refer to the page dedicated on
 :ref:`handler results <messenger-getting-handler-results>` for more information.
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\Console\\Messenger\\RunCommandMessage`
-    and :class:`Symfony\\Component\\Console\\Messenger\\RunCommandContext`
-    classes were introduced in Symfony 6.4.
-
 Trigger An External Process
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2153,8 +2342,9 @@ will take care of creating a new process with the parameters you passed::
 
     class CleanUpService
     {
-        public function __construct(private readonly MessageBusInterface $bus)
-        {
+        public function __construct(
+            private readonly MessageBusInterface $bus,
+        ) {
         }
 
         public function cleanUp(): void
@@ -2165,18 +2355,40 @@ will take care of creating a new process with the parameters you passed::
         }
     }
 
+If you want to use shell features such as redirections or pipes, use the static
+:method:`Symfony\\Component\\Process\\Messenger\\RunProcessMessage::fromShellCommandline` factory method::
+
+    use Symfony\Component\Messenger\MessageBusInterface;
+    use Symfony\Component\Process\Messenger\RunProcessMessage;
+
+    class CleanUpService
+    {
+        public function __construct(
+            private readonly MessageBusInterface $bus,
+        ) {
+        }
+
+        public function cleanUp(): void
+        {
+            $this->bus->dispatch(RunProcessMessage::fromShellCommandline('echo "Hello World" > var/log/hello.txt'));
+
+            // ...
+        }
+    }
+
+For more information, read the documentation about
+:ref:`using features from the OS shell <process-using-features-from-the-os-shell>`.
+
+.. versionadded:: 7.3
+
+    The ``RunProcessMessage::fromShellCommandline()`` method was introduced in Symfony 7.3.
+
 Once handled, the handler will return a
 :class:`Symfony\\Component\\Process\\Messenger\\RunProcessContext` which
 contains many useful information such as the exit code or the output of the
 process. You can refer to the page dedicated on
 :ref:`handler results <messenger-getting-handler-results>` for more information.
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\Process\\Messenger\\RunProcessMessage`
-    and :class:`Symfony\\Component\\Process\\Messenger\\RunProcessContext`
-    classes were introduced in Symfony 6.4.
-
 Pinging A Webservice
 --------------------
 
@@ -2217,11 +2429,6 @@ The handler will return a
 :class:`Symfony\\Contracts\\HttpClient\\ResponseInterface`, allowing you to
 gather and process information returned by the HTTP request.
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\HttpClient\\Messenger\\PingWebhookMessage`
-    class was introduced in Symfony 6.4.
-
 Getting Results from your Handlers
 ----------------------------------
 
@@ -2322,6 +2529,15 @@ wherever you need a query bus behavior instead of the ``MessageBusInterface``::
         }
     }
 
+You can also add new stamps when handling a message; they will be appended
+to the existing ones::
+
+    $this->handle(new SomeMessage($data), [new SomeStamp(), new AnotherStamp()]);
+
+.. versionadded:: 7.3
+
+    The ``$stamps`` parameter of the ``handle()`` method was introduced in Symfony 7.3.
+
 Customizing Handlers
 --------------------
 
@@ -2448,12 +2664,6 @@ A single handler class can handle multiple messages. For that add the
         }
     }
 
-.. deprecated:: 6.2
-
-    Implementing the :class:`Symfony\\Component\\Messenger\\Handler\\MessageSubscriberInterface`
-    is another way to handle multiple messages with one handler class. This
-    interface was deprecated in Symfony 6.2.
-
 .. _messenger-transactional-messages:
 
 Transactional Messages: Handle New Messages After Handling is Done
@@ -2572,7 +2782,7 @@ will not be rolled back.
 
     If ``WhenUserRegisteredThenSendWelcomeEmail`` throws an exception, that
     exception will be wrapped into a ``DelayedMessageHandlingException``. Using
-    ``DelayedMessageHandlingException::getExceptions`` will give you all
+    ``DelayedMessageHandlingException::getWrappedExceptions`` will give you all
     exceptions that are thrown while handling a message with the
     ``DispatchAfterCurrentBusStamp``.
 
@@ -2743,11 +2953,6 @@ provided in order to ease the declaration of these special handlers::
         }
     }
 
-.. versionadded:: 6.3
-
-    The :method:`Symfony\\Component\\Messenger\\Handler\\BatchHandlerTrait::getBatchSize`
-    method was introduced in Symfony 6.3.
-
 .. note::
 
     When the ``$ack`` argument of ``__invoke()`` is ``null``, the message is
@@ -2906,6 +3111,11 @@ and a different instance will be created per bus.
             $bus->middleware()->id('App\Middleware\AnotherMiddleware');
         };
 
+.. tip::
+
+    If you have installed the MakerBundle, you can use the ``make:messenger-middleware``
+    command to bootstrap the creation of your own messenger middleware.
+
 .. _middleware-doctrine:
 
 Middleware for Doctrine
@@ -3074,10 +3284,6 @@ of the process. For each, the event class is the event name:
 * :class:`Symfony\\Component\\Messenger\\Event\\WorkerStartedEvent`
 * :class:`Symfony\\Component\\Messenger\\Event\\WorkerStoppedEvent`
 
-.. versionadded:: 6.2
-
-    The ``WorkerRateLimitedEvent`` was introduced in Symfony 6.2.
-
 Additional Handler Arguments
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -3126,11 +3332,6 @@ Then your handler will look like this::
         }
     }
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Component\\Messenger\\Stamp\\HandlerArgumentsStamp`
-    was introduced in Symfony 6.2.
-
 Message Serializer For Custom Data Formats
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -3335,10 +3536,6 @@ an **event bus**. The event bus could have zero or more subscribers.
             $eventBus->middleware()->id('validation');
         };
 
-.. versionadded:: 6.2
-
-    The ``allow_no_senders`` option was introduced in Symfony 6.2.
-
 This will create three new services:
 
 * ``command.bus``: autowireable with the :class:`Symfony\\Component\\Messenger\\MessageBusInterface`
@@ -3363,9 +3560,6 @@ you can restrict each handler to a specific bus using the ``messenger.message_ha
         services:
             App\MessageHandler\SomeCommandHandler:
                 tags: [{ name: messenger.message_handler, bus: command.bus }]
-                # prevent handlers from being registered twice (or you can remove
-                # the MessageHandlerInterface that autoconfigure uses to find handlers)
-                autoconfigure: false
 
     .. code-block:: xml
 
@@ -3547,12 +3741,6 @@ will take care of this message to redispatch it through the same bus it was
 dispatched at first. You can also use the second argument of the ``RedispatchMessage``
 constructor to provide transports to use when redispatching the message.
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\Messenger\\Message\\RedispatchMessage`
-    and :class:`Symfony\\Component\\Messenger\\Handler\\RedispatchMessageHandler`
-    classes were introduced in Symfony 6.3.
-
 Learn more
 ----------
 
@@ -3576,3 +3764,5 @@ Learn more
 .. _`high connection churn`: https://www.rabbitmq.com/connections.html#high-connection-churn
 .. _`article about CQRS`: https://martinfowler.com/bliki/CQRS.html
 .. _`SSL context options`: https://php.net/context.ssl
+.. _`predefined constants`: https://www.php.net/pcntl.constants
+.. _`SQS CreateQueue API`: https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html
diff --git a/notifier.rst b/notifier.rst
index 9801432e9aa..49a1c2d533b 100644
--- a/notifier.rst
+++ b/notifier.rst
@@ -33,7 +33,14 @@ The notifier component supports the following channels:
   services like Slack and Telegram;
 * :ref:`Email channel <notifier-email-channel>` integrates the :doc:`Symfony Mailer </mailer>`;
 * Browser channel uses :ref:`flash messages <flash-messages>`.
-* :ref:`Push channel <notifier-push-channel>` sends notifications to phones and browsers via push notifications.
+* :ref:`Push channel <notifier-push-channel>` sends notifications to phones and
+  browsers via push notifications.
+* :ref:`Desktop channel <notifier-desktop-channel>` displays desktop notifications
+  on the same host machine.
+
+.. versionadded:: 7.2
+
+    The ``Desktop`` channel was introduced in Symfony 7.2.
 
 .. _notifier-sms-channel:
 
@@ -61,6 +68,7 @@ Service
 `AllMySms`_         **Install**: ``composer require symfony/all-my-sms-notifier`` \
                     **DSN**: ``allmysms://LOGIN:APIKEY@default?from=FROM`` \
                     **Webhook support**: No
+                    **Extra properties in SentMessage**: ``nbSms``, ``balance``, ``cost``
 `AmazonSns`_        **Install**: ``composer require symfony/amazon-sns-notifier`` \
                     **DSN**: ``sns://ACCESS_KEY:SECRET_KEY@default?region=REGION`` \
                     **Webhook support**: No
@@ -69,7 +77,7 @@ Service
                     **Webhook support**: No
 `Brevo`_            **Install**: ``composer require symfony/brevo-notifier`` \
                     **DSN**: ``brevo://API_KEY@default?sender=SENDER`` \
-                    **Webhook support**: No
+                    **Webhook support**: Yes
 `Clickatell`_       **Install**: ``composer require symfony/clickatell-notifier`` \
                     **DSN**: ``clickatell://ACCESS_TOKEN@default?from=FROM`` \
                     **Webhook support**: No
@@ -106,6 +114,9 @@ Service
 `LightSms`_         **Install**: ``composer require symfony/light-sms-notifier`` \
                     **DSN**: ``lightsms://LOGIN:TOKEN@default?from=PHONE`` \
                     **Webhook support**: No
+`LOX24`_            **Install**: ``composer require symfony/lox24-notifier`` \
+                    **DSN**: ``lox24://USER:TOKEN@default?from=FROM`` \
+                    **Webhook support**: No
 `Mailjet`_          **Install**: ``composer require symfony/mailjet-notifier`` \
                     **DSN**: ``mailjet://TOKEN@default?from=FROM`` \
                     **Webhook support**: No
@@ -129,9 +140,13 @@ Service
 `OvhCloud`_         **Install**: ``composer require symfony/ovh-cloud-notifier`` \
                     **DSN**: ``ovhcloud://APPLICATION_KEY:APPLICATION_SECRET@default?consumer_key=CONSUMER_KEY&service_name=SERVICE_NAME`` \
                     **Webhook support**: No
+                    **Extra properties in SentMessage**:: ``totalCreditsRemoved``
 `Plivo`_            **Install**: ``composer require symfony/plivo-notifier`` \
                     **DSN**: ``plivo://AUTH_ID:AUTH_TOKEN@default?from=FROM`` \
                     **Webhook support**: No
+`Primotexto`_       **Install**: ``composer require symfony/primotexto-notifier`` \
+                    **DSN**: ``primotexto://API_KEY@default?from=FROM`` \
+                    **Webhook support**: No
 `Redlink`_          **Install**: ``composer require symfony/redlink-notifier`` \
                     **DSN**: ``redlink://API_KEY:APP_KEY@default?from=SENDER_NAME&version=API_VERSION`` \
                     **Webhook support**: No
@@ -153,21 +168,36 @@ Service
 `Sinch`_            **Install**: ``composer require symfony/sinch-notifier`` \
                     **DSN**: ``sinch://ACCOUNT_ID:AUTH_TOKEN@default?from=FROM`` \
                     **Webhook support**: No
+`Sipgate`_          **Install**: ``composer require symfony/sipgate-notifier`` \
+                    **DSN**: ``sipgate://TOKEN_ID:TOKEN@default?senderId=SENDER_ID`` \
+                    **Webhook support**: No
+`SmsSluzba`_        **Install**: ``composer require symfony/sms-sluzba-notifier`` \
+                    **DSN**: ``sms-sluzba://USERNAME:PASSWORD@default`` \
+                    **Webhook support**: No
 `Smsapi`_           **Install**: ``composer require symfony/smsapi-notifier`` \
                     **DSN**: ``smsapi://TOKEN@default?from=FROM`` \
                     **Webhook support**: No
+`Smsbox`_           **Install**: ``composer require symfony/smsbox-notifier`` \
+                    **DSN**: ``smsbox://APIKEY@default?mode=MODE&strategy=STRATEGY&sender=SENDER`` \
+                    **Webhook support**: Yes
 `SmsBiuras`_        **Install**: ``composer require symfony/sms-biuras-notifier`` \
                     **DSN**: ``smsbiuras://UID:API_KEY@default?from=FROM&test_mode=0`` \
                     **Webhook support**: No
 `Smsc`_             **Install**: ``composer require symfony/smsc-notifier`` \
                     **DSN**: ``smsc://LOGIN:PASSWORD@default?from=FROM`` \
                     **Webhook support**: No
+`SMSense`_          **Install**: ``composer require smsense-notifier`` \
+                    **DSN**: ``smsense://API_TOKEN@default?from=FROM`` \
+                    **Webhook support**: No
 `SMSFactor`_        **Install**: ``composer require symfony/sms-factor-notifier`` \
                     **DSN**: ``sms-factor://TOKEN@default?sender=SENDER&push_type=PUSH_TYPE`` \
                     **Webhook support**: No
 `SpotHit`_          **Install**: ``composer require symfony/spot-hit-notifier`` \
                     **DSN**: ``spothit://TOKEN@default?from=FROM`` \
                     **Webhook support**: No
+`Sweego`_           **Install**: ``composer require symfony/sweego-notifier`` \
+                    **DSN**: ``sweego://API_KEY@default?region=REGION&campaign_type=CAMPAIGN_TYPE`` \
+                    **Webhook support**: Yes
 `Telnyx`_           **Install**: ``composer require symfony/telnyx-notifier`` \
                     **DSN**: ``telnyx://API_KEY@default?from=FROM&messaging_profile_id=MESSAGING_PROFILE_ID`` \
                     **Webhook support**: No
@@ -177,6 +207,9 @@ Service
 `Twilio`_           **Install**: ``composer require symfony/twilio-notifier`` \
                     **DSN**: ``twilio://SID:TOKEN@default?from=FROM`` \
                     **Webhook support**: Yes
+`Unifonic`_         **Install**: ``composer require symfony/unifonic-notifier`` \
+                    **DSN**: ``unifonic://APP_SID@default?from=FROM`` \
+                    **Webhook support**: No
 `Vonage`_           **Install**: ``composer require symfony/vonage-notifier`` \
                     **DSN**: ``vonage://KEY:SECRET@default?from=FROM`` \
                     **Webhook support**: Yes
@@ -185,41 +218,36 @@ Service
                     **Webhook support**: No
 ==================  ====================================================================================================================================
 
-.. versionadded:: 6.1
-
-    The 46elks, OrangeSms, KazInfoTeh and Sendberry integrations were introduced in Symfony 6.1.
-    The ``no_stop_clause`` option in ``OvhCloud`` DSN was introduced in Symfony 6.1.
-    The ``test`` option in ``Smsapi`` DSN was introduced in Symfony 6.1.
-
-.. versionadded:: 6.2
+.. tip::
 
-    The ContactEveryone and SMSFactor integrations were introduced in Symfony 6.2.
+    Use :doc:`Symfony configuration secrets </configuration/secrets>` to securely
+    store your API tokens.
 
-.. versionadded:: 6.3
+.. tip::
 
-    The Bandwith, iSendPro, Plivo, RingCentral, SimpleTextin and Termii integrations
-    were introduced in Symfony 6.3.
-    The ``from`` option in ``Smsapi`` DSN is optional since Symfony 6.3.
+    Some third party transports, when using the API, support status callbacks
+    via webhooks. See the :doc:`Webhook documentation </webhook>` for more
+    details.
 
-.. versionadded:: 6.4
+.. versionadded:: 7.1
 
-    The `Redlink`_ and `Brevo`_ integrations were introduced in Symfony 6.4.
+    The ``Smsbox``, ``SmsSluzba``, ``SMSense``, ``LOX24`` and ``Unifonic``
+    integrations were introduced in Symfony 7.1.
 
-.. deprecated:: 6.4
+.. versionadded:: 7.2
 
-    The `Sendinblue`_ integration is deprecated since
-    Symfony 6.4, use the `Brevo`_ integration instead.
+    The ``Primotexto``, ``Sipgate`` and ``Sweego`` integrations were introduced in Symfony 7.2.
 
-.. tip::
+.. versionadded:: 7.3
 
-    Use :doc:`Symfony configuration secrets </configuration/secrets>` to securely
-    store your API tokens.
+    Webhook support for the ``Brevo`` integration was introduced in Symfony 7.3.
+    The extra properties in ``SentMessage`` for ``AllMySms`` and ``OvhCloud``
+    providers were introduced in Symfony 7.3 too.
 
-.. tip::
+.. deprecated:: 7.1
 
-    Some third party transports, when using the API, support status callbacks
-    via webhooks. See the :doc:`Webhook documentation </webhook>` for more
-    details.
+    The `Sms77`_ integration is deprecated since
+    Symfony 7.1, use the `Seven.io`_ integration instead.
 
 To enable a texter, add the correct DSN in your ``.env`` file and
 configure the ``texter_transports``:
@@ -310,14 +338,6 @@ send SMS messages::
         }
     }
 
-.. versionadded:: 6.2
-
-    The 3rd argument of ``SmsMessage`` (``$from``) was introduced in Symfony 6.2.
-
-.. versionadded:: 6.3
-
-    The 4th argument of ``SmsMessage`` (``$options``) was introduced in Symfony 6.3.
-
 The ``send()`` method returns a variable of type
 :class:`Symfony\\Component\\Notifier\\Message\\SentMessage` which provides
 information such as the message ID and the original message contents.
@@ -338,37 +358,70 @@ The chat channel is used to send chat messages to users by using
 :class:`Symfony\\Component\\Notifier\\Chatter` classes. Symfony provides
 integration with these chat services:
 
-=======================================  ====================================  =============================================================================
-Service                                  Package                               DSN
-=======================================  ====================================  =============================================================================
-`AmazonSns`_                             ``symfony/amazon-sns-notifier``       ``sns://ACCESS_KEY:SECRET_KEY@default?region=REGION``
-`Chatwork`_                              ``symfony/chatwork-notifier``         ``chatwork://API_TOKEN@default?room_id=ID``
-`Discord`_                               ``symfony/discord-notifier``          ``discord://TOKEN@default?webhook_id=ID``
-`FakeChat`_                              ``symfony/fake-chat-notifier``        ``fakechat+email://default?to=TO&from=FROM`` or ``fakechat+logger://default``
-`Firebase`_                              ``symfony/firebase-notifier``         ``firebase://USERNAME:PASSWORD@default``
-`Gitter`_                                ``symfony/gitter-notifier``           ``gitter://TOKEN@default?room_id=ROOM_ID``
-`GoogleChat`_                            ``symfony/google-chat-notifier``      ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY``
-`LINE Notify`_                           ``symfony/line-notify-notifier``      ``linenotify://TOKEN@default``
-`LinkedIn`_                              ``symfony/linked-in-notifier``        ``linkedin://TOKEN:USER_ID@default``
-`Mastodon`_                              ``symfony/mastodon-notifier``         ``mastodon://ACCESS_TOKEN@HOST``
-`Mattermost`_                            ``symfony/mattermost-notifier``       ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL``
-`Mercure`_                               ``symfony/mercure-notifier``          ``mercure://HUB_ID?topic=TOPIC``
-`MicrosoftTeams`_                        ``symfony/microsoft-teams-notifier``  ``microsoftteams://default/PATH``
-`RocketChat`_                            ``symfony/rocket-chat-notifier``      ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL``
-`Slack`_                                 ``symfony/slack-notifier``            ``slack://TOKEN@default?channel=CHANNEL``
-`Telegram`_                              ``symfony/telegram-notifier``         ``telegram://TOKEN@default?channel=CHAT_ID``
-`Twitter`_                               ``symfony/twitter-notifier``          ``twitter://API_KEY:API_SECRET:ACCESS_TOKEN:ACCESS_SECRET@default``
-`Zendesk`_                               ``symfony/zendesk-notifier``          ``zendesk://EMAIL:TOKEN@SUBDOMAIN``
-`Zulip`_                                 ``symfony/zulip-notifier``            ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL``
-======================================   ====================================  =============================================================================
-
-.. versionadded:: 6.2
-
-    The Zendesk and Chatwork integration were introduced in Symfony 6.2.
-
-.. versionadded:: 6.3
-
-    The LINE Notify, Mastodon and Twitter integrations were introduced in Symfony 6.3.
+======================================   =====================================================================================
+Service
+======================================   =====================================================================================
+`AmazonSns`_                             **Install**: ``composer require symfony/amazon-sns-notifier`` \
+                                         **DSN**: ``sns://ACCESS_KEY:SECRET_KEY@default?region=REGION``
+`Bluesky`_                               **Install**: ``composer require symfony/bluesky-notifier`` \
+                                         **DSN**: ``bluesky://USERNAME:PASSWORD@default``
+                                         **Extra properties in SentMessage**: ``cid``
+`Chatwork`_                              **Install**: ``composer require symfony/chatwork-notifier`` \
+                                         **DSN**: ``chatwork://API_TOKEN@default?room_id=ID``
+`Discord`_                               **Install**: ``composer require symfony/discord-notifier`` \
+                                         **DSN**: ``discord://TOKEN@default?webhook_id=ID``
+`FakeChat`_                              **Install**: ``composer require symfony/fake-chat-notifier`` \
+                                         **DSN**: ``fakechat+email://default?to=TO&from=FROM`` or ``fakechat+logger://default``
+`Firebase`_                              **Install**: ``composer require symfony/firebase-notifier`` \
+                                         **DSN**: ``firebase://USERNAME:PASSWORD@default``
+`GoogleChat`_                            **Install**: ``composer require symfony/google-chat-notifier`` \
+                                         **DSN**: ``googlechat://ACCESS_KEY:ACCESS_TOKEN@default/SPACE?thread_key=THREAD_KEY``
+`LINE Bot`_                              **Install**: ``composer require symfony/line-bot-notifier`` \
+                                         **DSN**: ``linebot://TOKEN@default?receiver=RECEIVER``
+`LINE Notify`_                           **Install**: ``composer require symfony/line-notify-notifier`` \
+                                         **DSN**: ``linenotify://TOKEN@default``
+`LinkedIn`_                              **Install**: ``composer require symfony/linked-in-notifier`` \
+                                         **DSN**: ``linkedin://TOKEN:USER_ID@default``
+`Mastodon`_                              **Install**: ``composer require symfony/mastodon-notifier`` \
+                                         **DSN**: ``mastodon://ACCESS_TOKEN@HOST``
+`Matrix`_                                **Install**: ``composer require symfony/matrix-notifier`` \
+                                         **DSN**: ``matrix://HOST:PORT/?accessToken=ACCESSTOKEN&ssl=SSL``
+`Mattermost`_                            **Install**: ``composer require symfony/mattermost-notifier`` \
+                                         **DSN**: ``mattermost://ACCESS_TOKEN@HOST/PATH?channel=CHANNEL``
+`Mercure`_                               **Install**: ``composer require symfony/mercure-notifier`` \
+                                         **DSN**: ``mercure://HUB_ID?topic=TOPIC``
+`MicrosoftTeams`_                        **Install**: ``composer require symfony/microsoft-teams-notifier`` \
+                                         **DSN**: ``microsoftteams://default/PATH``
+`RocketChat`_                            **Install**: ``composer require symfony/rocket-chat-notifier`` \
+                                         **DSN**: ``rocketchat://TOKEN@ENDPOINT?channel=CHANNEL``
+`Slack`_                                 **Install**: ``composer require symfony/slack-notifier`` \
+                                         **DSN**: ``slack://TOKEN@default?channel=CHANNEL``
+`Telegram`_                              **Install**: ``composer require symfony/telegram-notifier`` \
+                                         **DSN**: ``telegram://TOKEN@default?channel=CHAT_ID``
+`Twitter`_                               **Install**: ``composer require symfony/twitter-notifier`` \
+                                         **DSN**: ``twitter://API_KEY:API_SECRET:ACCESS_TOKEN:ACCESS_SECRET@default``
+`Zendesk`_                               **Install**: ``composer require symfony/zendesk-notifier`` \
+                                         **DSN**: ``zendesk://EMAIL:TOKEN@SUBDOMAIN``
+`Zulip`_                                 **Install**: ``composer require symfony/zulip-notifier`` \
+                                         **DSN**: ``zulip://EMAIL:TOKEN@HOST?channel=CHANNEL``
+======================================   =====================================================================================
+
+.. versionadded:: 7.1
+
+    The ``Bluesky`` integration was introduced in Symfony 7.1.
+
+.. versionadded:: 7.2
+
+    The ``LINE Bot`` integration was introduced in Symfony 7.2.
+
+.. deprecated:: 7.2
+
+    The ``Gitter`` integration was removed in Symfony 7.2 because that service
+    no longer provides an API.
+
+.. versionadded:: 7.3
+
+    The ``Matrix`` integration was introduced in Symfony 7.3.
 
 .. warning::
 
@@ -551,33 +604,34 @@ The push channel is used to send notifications to users by using
 :class:`Symfony\\Component\\Notifier\\Texter` classes. Symfony provides
 integration with these push services:
 
-===============  ====================================  ==============================================================================
-Service          Package                               DSN
-===============  ====================================  ==============================================================================
-`Engagespot`_    ``symfony/engagespot-notifier``       ``engagespot://API_KEY@default?campaign_name=CAMPAIGN_NAME``
-`Expo`_          ``symfony/expo-notifier``             ``expo://Token@default``
-`Novu`_          ``symfony/novu-notifier``             ``novu://API_KEY@default``
-`Ntfy`_          ``symfony/ntfy-notifier``             ``ntfy://default/TOPIC``
-`OneSignal`_     ``symfony/one-signal-notifier``       ``onesignal://APP_ID:API_KEY@default?defaultRecipientId=DEFAULT_RECIPIENT_ID``
-`PagerDuty`_     ``symfony/pager-duty-notifier``       ``pagerduty://TOKEN@SUBDOMAIN``
-`Pushover`_      ``symfony/pushover-notifier``         ``pushover://USER_KEY:APP_TOKEN@default``
-===============  ====================================  ==============================================================================
-
-.. versionadded:: 6.1
-
-    The Engagespot integration was introduced in Symfony 6.1.
-
-.. versionadded:: 6.3
-
-    The PagerDuty and Pushover integrations were introduced in Symfony 6.3.
-
-.. versionadded:: 6.4
-
-    The Novu, Ntfy and GoIP integrations were introduced in Symfony 6.4.
+===============  =======================================================================================
+Service
+===============  =======================================================================================
+`Engagespot`_    **Install**: ``composer require symfony/engagespot-notifier`` \
+                 **DSN**: ``engagespot://API_KEY@default?campaign_name=CAMPAIGN_NAME``
+`Expo`_          **Install**: ``composer require symfony/expo-notifier`` \
+                 **DSN**: ``expo://TOKEN@default``
+`Novu`_          **Install**: ``composer require symfony/novu-notifier`` \
+                 **DSN**: ``novu://API_KEY@default``
+`Ntfy`_          **Install**: ``composer require symfony/ntfy-notifier`` \
+                 **DSN**: ``ntfy://default/TOPIC``
+`OneSignal`_     **Install**: ``composer require symfony/one-signal-notifier`` \
+                 **DSN**: ``onesignal://APP_ID:API_KEY@default?defaultRecipientId=DEFAULT_RECIPIENT_ID``
+`PagerDuty`_     **Install**: ``composer require symfony/pager-duty-notifier`` \
+                 **DSN**: ``pagerduty://TOKEN@SUBDOMAIN``
+`Pushover`_      **Install**: ``composer require symfony/pushover-notifier`` \
+                 **DSN**: ``pushover://USER_KEY:APP_TOKEN@default``
+`Pushy`_         **Install**: ``composer require symfony/pushy-notifier`` \
+                 **DSN**: ``pushy://API_KEY@default``
+===============  =======================================================================================
 
 To enable a texter, add the correct DSN in your ``.env`` file and
 configure the ``texter_transports``:
 
+.. versionadded:: 7.1
+
+    The `Pushy`_ integration was introduced in Symfony 7.1.
+
 .. code-block:: bash
 
     # .env
@@ -625,6 +679,124 @@ configure the ``texter_transports``:
             ;
         };
 
+.. _notifier-desktop-channel:
+
+Desktop Channel
+~~~~~~~~~~~~~~~
+
+The desktop channel is used to display local desktop notifications on the same
+host machine using :class:`Symfony\\Component\\Notifier\\Texter` classes. Currently,
+Symfony is integrated with the following providers:
+
+===============  ================================================  ==============================================================================
+Provider         Install                                           DSN
+===============  ================================================  ==============================================================================
+`JoliNotif`_     ``composer require symfony/joli-notif-notifier``  ``jolinotif://default``
+===============  ================================================  ==============================================================================
+
+.. versionadded:: 7.2
+
+    The JoliNotif bridge was introduced in Symfony 7.2.
+
+If you are using :ref:`Symfony Flex <symfony-flex>`, installing that package will
+also create the necessary environment variable and configuration. Otherwise, you'll
+need to add the following manually:
+
+1) Add the correct DSN in your ``.env`` file:
+
+.. code-block:: bash
+
+    # .env
+    JOLINOTIF=jolinotif://default
+
+2) Update the Notifier configuration to add a new texter transport:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/notifier.yaml
+        framework:
+            notifier:
+                texter_transports:
+                    jolinotif: '%env(JOLINOTIF)%'
+
+    .. code-block:: xml
+
+        <!-- config/packages/notifier.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony
+                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:notifier>
+                    <framework:texter-transport name="jolinotif">
+                        %env(JOLINOTIF)%
+                    </framework:texter-transport>
+                </framework:notifier>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/notifier.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->notifier()
+                ->texterTransport('jolinotif', env('JOLINOTIF'))
+            ;
+        };
+
+Now you can send notifications to your desktop as follows::
+
+    // src/Notifier/SomeService.php
+    use Symfony\Component\Notifier\Message\DesktopMessage;
+    use Symfony\Component\Notifier\TexterInterface;
+    // ...
+
+    class SomeService
+    {
+        public function __construct(
+            private TexterInterface $texter,
+        ) {
+        }
+
+        public function notifyNewSubscriber(User $user): void
+        {
+            $message = new DesktopMessage(
+                'New subscription! 🎉',
+                sprintf('%s is a new subscriber', $user->getFullName())
+            );
+
+            $this->texter->send($message);
+        }
+    }
+
+These notifications can be customized further, and depending on your operating system,
+they may support features like custom sounds, icons, and more::
+
+    use Symfony\Component\Notifier\Bridge\JoliNotif\JoliNotifOptions;
+    // ...
+
+    $options = (new JoliNotifOptions())
+        ->setIconPath('/path/to/icons/error.png')
+        ->setExtraOption('sound', 'sosumi')
+        ->setExtraOption('url', 'https://example.com');
+
+    $message = new DesktopMessage('Production is down', <<<CONTENT
+        ❌ Server prod-1 down
+        ❌ Server prod-2 down
+        ✅ Network is up
+        CONTENT, $options);
+
+    $texter->send($message);
+
 Configure to use Failover or Round-Robin Transports
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -928,18 +1100,15 @@ and its ``asChatMessage()`` method::
 
 The
 :class:`Symfony\\Component\\Notifier\\Notification\\SmsNotificationInterface`,
-:class:`Symfony\\Component\\Notifier\\Notification\\EmailNotificationInterface`
-and
+:class:`Symfony\\Component\\Notifier\\Notification\\EmailNotificationInterface`,
 :class:`Symfony\\Component\\Notifier\\Notification\\PushNotificationInterface`
+and
+:class:`Symfony\\Component\\Notifier\\Notification\\DesktopNotificationInterface`
 also exists to modify messages sent to those channels.
 
 Customize Browser Notifications (Flash Messages)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.1
-
-    Support for customizing importance levels was introduced in Symfony 6.1.
-
 The default behavior for browser channel notifications is to add a
 :ref:`flash message <flash-messages>` with ``notification`` as its key.
 
@@ -999,11 +1168,6 @@ You can benefit from this class by using it directly or extending the
 
 See :ref:`testing documentation <notifier-assertions>` for the list of available assertions.
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Bundle\\FrameworkBundle\\Test\\NotificationAssertionsTrait`
-    was introduced in Symfony 6.2.
-
 Disabling Delivery
 ------------------
 
@@ -1106,6 +1270,7 @@ is dispatched. Listeners receive a
 .. _`AllMySms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/AllMySms/README.md
 .. _`AmazonSns`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/AmazonSns/README.md
 .. _`Bandwidth`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Bandwidth/README.md
+.. _`Bluesky`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Bluesky/README.md
 .. _`Brevo`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Brevo/README.md
 .. _`Chatwork`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Chatwork/README.md
 .. _`Clickatell`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Clickatell/README.md
@@ -1119,18 +1284,21 @@ is dispatched. Listeners receive a
 .. _`Firebase`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Firebase/README.md
 .. _`FreeMobile`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/FreeMobile/README.md
 .. _`GatewayApi`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GatewayApi/README.md
-.. _`Gitter`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Gitter/README.md
-.. _`GoIP`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GoIp/README.md
+.. _`GoIP`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GoIP/README.md
 .. _`GoogleChat`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/GoogleChat/README.md
 .. _`Infobip`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Infobip/README.md
 .. _`Iqsms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Iqsms/README.md
 .. _`iSendPro`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Isendpro/README.md
+.. _`JoliNotif`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/JoliNotif/README.md
 .. _`KazInfoTeh`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/KazInfoTeh/README.md
+.. _`LINE Bot`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LineBot/README.md
 .. _`LINE Notify`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LineNotify/README.md
 .. _`LightSms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LightSms/README.md
 .. _`LinkedIn`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/LinkedIn/README.md
+.. _`LOX24`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Lox24/README.md
 .. _`Mailjet`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Mailjet/README.md
 .. _`Mastodon`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Mastodon/README.md
+.. _`Matrix`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Matrix/README.md
 .. _`Mattermost`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Mattermost/README.md
 .. _`Mercure`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Mercure/README.md
 .. _`MessageBird`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/MessageBird/README.md
@@ -1146,7 +1314,9 @@ is dispatched. Listeners receive a
 .. _`OvhCloud`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/OvhCloud/README.md
 .. _`PagerDuty`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/PagerDuty/README.md
 .. _`Plivo`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Plivo/README.md
+.. _`Primotexto`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Primotexto/README.md
 .. _`Pushover`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Pushover/README.md
+.. _`Pushy`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Pushy/README.md
 .. _`Redlink`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Redlink/README.md
 .. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt
 .. _`RingCentral`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/RingCentral/README.md
@@ -1154,19 +1324,26 @@ is dispatched. Listeners receive a
 .. _`SMSFactor`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SmsFactor/README.md
 .. _`Sendberry`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sendberry/README.md
 .. _`Sendinblue`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sendinblue/README.md
+.. _`Seven.io`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sevenio/README.md
 .. _`SimpleTextin`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SimpleTextin/README.md
 .. _`Sinch`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sinch/README.md
+.. _`Sipgate`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sipgate/README.md
 .. _`Slack`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Slack/README.md
 .. _`Sms77`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sms77/README.md
 .. _`SmsBiuras`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SmsBiuras/README.md
+.. _`Smsbox`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Smsbox/README.md
 .. _`Smsapi`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Smsapi/README.md
 .. _`Smsc`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Smsc/README.md
+.. _`SMSense`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SMSense/README.md
+.. _`SmsSluzba`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SmsSluzba/README.md
 .. _`SpotHit`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/SpotHit/README.md
+.. _`Sweego`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Sweego/README.md
 .. _`Telegram`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Telegram/README.md
 .. _`Telnyx`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Telnyx/README.md
 .. _`TurboSms`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/TurboSms/README.md
 .. _`Twilio`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Twilio/README.md
 .. _`Twitter`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Twitter/README.md
+.. _`Unifonic`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Unifonic/README.md
 .. _`Vonage`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Vonage/README.md
 .. _`Yunpian`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Yunpian/README.md
 .. _`Zendesk`: https://github.com/symfony/symfony/blob/{version}/src/Symfony/Component/Notifier/Bridge/Zendesk/README.md
diff --git a/object_mapper.rst b/object_mapper.rst
new file mode 100644
index 00000000000..625466ffefc
--- /dev/null
+++ b/object_mapper.rst
@@ -0,0 +1,738 @@
+Object Mapper
+=============
+
+.. versionadded:: 7.3
+
+    The ObjectMapper component was introduced in Symfony 7.3 as an
+    :doc:`experimental feature </contributing/code/experimental>`.
+
+This component transforms one object into another, simplifying tasks such as
+converting DTOs (Data Transfer Objects) into entities or vice versa. It can also
+be helpful when decoupling API input/output from internal models, particularly
+when working with legacy code or implementing hexagonal architectures.
+
+Installation
+------------
+
+Run this command to install the component before using it:
+
+.. code-block:: terminal
+
+    $ composer require symfony/object-mapper
+
+Usage
+-----
+
+The object mapper service will be :doc:`autowired </service_container/autowiring>`
+automatically in controllers or services when type-hinting for
+:class:`Symfony\\Component\\ObjectMapper\\ObjectMapperInterface`::
+
+    // src/Controller/UserController.php
+    namespace App\Controller;
+
+    use App\Dto\UserInput;
+    use App\Entity\User;
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\ObjectMapper\ObjectMapperInterface;
+
+    class UserController extends AbstractController
+    {
+        public function updateUser(UserInput $userInput, ObjectMapperInterface $objectMapper): Response
+        {
+            $user = new User();
+            // Map properties from UserInput to User
+            $objectMapper->map($userInput, $user);
+
+            // ... persist $user and return response
+            return new Response('User updated!');
+        }
+    }
+
+Basic Mapping
+-------------
+
+The core functionality is provided by the ``map()`` method. It accepts a
+source object and maps its properties to a target. The target can either be
+a class name (to create a new instance) or an existing object (to update it).
+
+Mapping to a New Object
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Provide the target class name as the second argument::
+
+    use App\Dto\ProductInput;
+    use App\Entity\Product;
+    use Symfony\Component\ObjectMapper\ObjectMapper;
+
+    $productInput = new ProductInput();
+    $productInput->name = 'Wireless Mouse';
+    $productInput->sku = 'WM-1024';
+
+    $mapper = new ObjectMapper();
+    // creates a new Product instance and maps properties from $productInput
+    $product = $mapper->map($productInput, Product::class);
+
+    // $product is now an instance of Product
+    // with $product->name = 'Wireless Mouse' and $product->sku = 'WM-1024'
+
+Mapping to an Existing Object
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Provide an existing object instance as the second argument to update it::
+
+    use App\Dto\ProductUpdateInput;
+    use App\Entity\Product;
+    use Symfony\Component\ObjectMapper\ObjectMapper;
+
+    $product = $productRepository->find(1);
+
+    $updateInput = new ProductUpdateInput();
+    $updateInput->price = 99.99;
+
+    $mapper = new ObjectMapper();
+    // updates the existing $product instance
+    $mapper->map($updateInput, $product);
+
+    // $product->price is now 99.99
+
+Mapping from ``stdClass``
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The source object can also be an instance of ``stdClass``. This can be
+useful when working with decoded JSON data or loosely typed input::
+
+    use App\Entity\Product;
+    use Symfony\Component\ObjectMapper\ObjectMapper;
+
+    $productData = new \stdClass();
+    $productData->name = 'Keyboard';
+    $productData->sku = 'KB-001';
+
+    $mapper = new ObjectMapper();
+    $product = $mapper->map($productData, Product::class);
+
+    // $product is an instance of Product with properties mapped from $productData
+
+Configuring Mapping with Attributes
+-----------------------------------
+
+ObjectMapper uses PHP attributes to configure how properties are mapped.
+The primary attribute is :class:`Symfony\\Component\\ObjectMapper\\Attribute\\Map`.
+
+Defining the Default Target Class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Apply ``#[Map]`` to the source class to define its default mapping target::
+
+    // src/Dto/ProductInput.php
+    namespace App\Dto;
+
+    use App\Entity\Product;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: Product::class)]
+    class ProductInput
+    {
+        public string $name = '';
+        public string $sku = '';
+    }
+
+    // now you can call map() without the second argument if ProductInput is the source:
+    $mapper = new ObjectMapper();
+    $product = $mapper->map($productInput); // Maps to Product automatically
+
+Configuring Property Mapping
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can apply the ``#[Map]`` attribute to properties to customize their mapping behavior:
+
+* ``target``: Specifies the name of the property in the target object;
+* ``source``: Specifies the name of the property in the source object (useful
+  when mapping is defined on the target, see below);
+* ``if``: Defines a condition for mapping the property;
+* ``transform``: Applies a transformation to the value before mapping.
+
+This is how it looks in practice::
+
+    // src/Dto/OrderInput.php
+    namespace App\Dto;
+
+    use App\Entity\Order;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: Order::class)]
+    class OrderInput
+    {
+        // map 'customerEmail' from source to 'email' in target
+        #[Map(target: 'email')]
+        public string $customerEmail = '';
+
+        // do not map this property at all
+        #[Map(if: false)]
+        public string $internalNotes = '';
+
+        // only map 'discountCode' if it's a non-empty string
+        // (uses PHP's strlen() function as a condition)
+        #[Map(if: 'strlen')]
+        public ?string $discountCode = null;
+    }
+
+By default, if a property exists in the source but not in the target, it is
+ignored. If a property exists in both and no ``#[Map]`` is defined, the mapper
+assumes a direct mapping when names match.
+
+Conditional Mapping with Services
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For complex conditions, you can use a dedicated service implementing
+:class:`Symfony\\Component\\ObjectMapper\\ConditionCallableInterface`::
+
+    // src/ObjectMapper/IsShippableCondition.php
+    namespace App\ObjectMapper;
+
+    use App\Dto\OrderInput;
+    use App\Entity\Order; // Target type hint
+    use Symfony\Component\ObjectMapper\ConditionCallableInterface;
+
+    /**
+     * @implements ConditionCallableInterface<OrderInput, Order>
+     */
+    final class IsShippableCondition implements ConditionCallableInterface
+    {
+        public function __invoke(mixed $value, object $source, ?object $target): bool
+        {
+            // example: Only map shipping address if order total is above 50
+            return $source->total > 50;
+        }
+    }
+
+Then, pass the service name (its class name by default) to the ``if`` parameter::
+
+    // src/Dto/OrderInput.php
+    namespace App\Dto;
+
+    use App\Entity\Order;
+    use App\ObjectMapper\IsShippableCondition;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: Order::class)]
+    class OrderInput
+    {
+        public float $total = 0.0;
+
+        #[Map(if: IsShippableCondition::class)]
+        public ?string $shippingAddress = null;
+    }
+
+For this to work, ``IsShippableCondition`` must be registered as a service.
+
+.. _object_mapper-conditional-property-target:
+
+Conditional Property Mapping based on Target
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When a source class maps to multiple targets, you may want to include or exclude
+certain properties depending on which target is being used. Use the
+:class:`Symfony\\Component\\ObjectMapper\\Condition\\TargetClass` condition within
+the ``if`` parameter of a property's ``#[Map]`` attribute to achieve this.
+
+This pattern is useful for building multiple representations (e.g., public vs. admin)
+from a given source object, and can be used as an alternative to
+:ref:`serialization groups <serializer-groups-attribute>`::
+
+    // src/Entity/User.php
+    namespace App\Entity;
+
+    use App\Dto\AdminUserProfile;
+    use App\Dto\PublicUserProfile;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+    use Symfony\Component\ObjectMapper\Condition\TargetClass;
+
+    // this User entity can be mapped to two different DTOs
+    #[Map(target: PublicUserProfile::class)]
+    #[Map(target: AdminUserProfile::class)]
+    class User
+    {
+        // map 'lastLoginIp' to 'ipAddress' ONLY when the target is AdminUserProfile
+        #[Map(target: 'ipAddress', if: new TargetClass(AdminUserProfile::class))]
+        public ?string $lastLoginIp = '192.168.1.100';
+
+        // map 'registrationDate' to 'memberSince' for both targets
+        #[Map(target: 'memberSince')]
+        public \DateTimeImmutable $registrationDate;
+
+        public function __construct() {
+            $this->registrationDate = new \DateTimeImmutable();
+        }
+    }
+
+    // src/Dto/PublicUserProfile.php
+    namespace App\Dto;
+    class PublicUserProfile
+    {
+        public \DateTimeImmutable $memberSince;
+        // no $ipAddress property here
+    }
+
+    // src/Dto/AdminUserProfile.php
+    namespace App\Dto;
+    class AdminUserProfile
+    {
+        public \DateTimeImmutable $memberSince;
+        public ?string $ipAddress = null; // mapped from lastLoginIp
+    }
+
+    // usage:
+    $user = new User();
+    $mapper = new ObjectMapper();
+
+    $publicProfile = $mapper->map($user, PublicUserProfile::class);
+    // no IP address available
+
+    $adminProfile = $mapper->map($user, AdminUserProfile::class);
+    // $adminProfile->ipAddress = '192.168.1.100'
+
+Transforming Values
+-------------------
+
+Use the ``transform`` option within ``#[Map]`` to change a value before it is
+assigned to the target. This can be a callable (e.g., a built-in PHP function,
+static method, or anonymous function) or a service implementing
+:class:`Symfony\\Component\\ObjectMapper\\TransformCallableInterface`.
+
+Using Callables
+~~~~~~~~~~~~~~~
+
+Consider the following static utility method::
+
+    // src/Util/PriceFormatter.php
+    namespace App\Util;
+
+    class PriceFormatter
+    {
+        public static function format(float $value, object $source): string
+        {
+            return number_format($value, 2, '.', '');
+        }
+    }
+
+You can use that method to format a property when mapping it::
+
+    // src/Dto/ProductInput.php
+    namespace App\Dto;
+
+    use App\Entity\Product;
+    use App\Util\PriceFormatter;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: Product::class)]
+    class ProductInput
+    {
+        // use a static method from another class for formatting
+        #[Map(target: 'displayPrice', transform: [PriceFormatter::class, 'format'])]
+        public float $price = 0.0;
+
+        // can also use built-in PHP functions
+        #[Map(transform: 'intval')]
+        public string $stockLevel = '100';
+    }
+
+Using Transformer Services
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Similar to conditions, complex transformations can be encapsulated in services
+implementing :class:`Symfony\\Component\\ObjectMapper\\TransformCallableInterface`::
+
+    // src/ObjectMapper/FullNameTransformer.php
+    namespace App\ObjectMapper;
+
+    use App\Dto\UserInput;
+    use App\Entity\User;
+    use Symfony\Component\ObjectMapper\TransformCallableInterface;
+
+    /**
+     * @implements TransformCallableInterface<UserInput, User>
+     */
+    final class FullNameTransformer implements TransformCallableInterface
+    {
+        public function __invoke(mixed $value, object $source, ?object $target): mixed
+        {
+            return trim($source->firstName . ' ' . $source->lastName);
+        }
+    }
+
+Then, use this service to format the mapped property::
+
+    // src/Dto/UserInput.php
+    namespace App\Dto;
+
+    use App\Entity\User;
+    use App\ObjectMapper\FullNameTransformer;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: User::class)]
+    class UserInput
+    {
+        // this property's value will be generated by the transformer
+        #[Map(target: 'fullName', transform: FullNameTransformer::class)]
+        public string $firstName = '';
+
+        public string $lastName = '';
+    }
+
+Class-Level Transformation
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can define a transformation at the class level using the ``transform``
+parameter on the ``#[Map]`` attribute. This callable runs *after* the target
+object is created (if the target is a class name, ``newInstanceWithoutConstructor``
+is used), but *before* any properties are mapped. It must return a correctly
+initialized instance of the target class (replacing the one created by the mapper
+if needed)::
+
+    // src/Dto/LegacyUserData.php
+    namespace App\Dto;
+
+    use App\Entity\User;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    // use a static factory method on the target User class for instantiation
+    #[Map(target: User::class, transform: [User::class, 'createFromLegacy'])]
+    class LegacyUserData
+    {
+        public int $userId = 0;
+        public string $name = '';
+    }
+
+And the related target object must define the ``createFromLegacy()`` method::
+
+    // src/Entity/User.php
+    namespace App\Entity;
+    class User
+    {
+        public string $name = '';
+        private int $legacyId = 0;
+
+        // uses a private constructor to avoid direct instantiation
+        private function __construct() {}
+
+        public static function createFromLegacy(mixed $value, object $source): self
+        {
+            // $value is the initially created (empty) User object
+            // $source is the LegacyUserData object
+            $user = new self();
+            $user->legacyId = $source->userId;
+
+            // property mapping will happen *after* this method returns $user
+            return $user;
+        }
+    }
+
+Mapping Multiple Targets
+------------------------
+
+A source class can be configured to map to multiple different target classes.
+Apply the ``#[Map]`` attribute multiple times at the class level, typically
+using the ``if`` condition to determine which target is appropriate based on the
+source object's state or other logic::
+
+    // src/Dto/EventInput.php
+    namespace App\Dto;
+
+    use App\Entity\OnlineEvent;
+    use App\Entity\PhysicalEvent;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: OnlineEvent::class, if: [self::class, 'isOnline'])]
+    #[Map(target: PhysicalEvent::class, if: [self::class, 'isPhysical'])]
+    class EventInput
+    {
+        public string $type = 'online'; // e.g., 'online' or 'physical'
+        public string $title = '';
+
+        /**
+         * In class-level conditions, $value is null.
+         */
+        public static function isOnline(?mixed $value, object $source): bool
+        {
+            return 'online' === $source->type;
+        }
+
+        public static function isPhysical(?mixed $value, object $source): bool
+        {
+            return 'physical' === $source->type;
+        }
+    }
+
+    // consider that the src/Entity/OnlineEvent.php and PhysicalEvent.php
+    // files exist and define the needed classes
+
+    // usage:
+    $eventInput = new EventInput();
+    $eventInput->type = 'physical';
+    $mapper = new ObjectMapper();
+    $event = $mapper->map($eventInput); // automatically maps to PhysicalEvent
+
+Mapping Based on Target Properties (Source Mapping)
+---------------------------------------------------
+
+Sometimes, it's more convenient to define how a target object should retrieve
+its values from a source, especially when working with external data formats.
+This is done using the ``source`` parameter in the ``#[Map]`` attribute on the
+target class's properties.
+
+Note that if both the ``source`` and the ``target`` classes define the ``#[Map]``
+attribute, the ``source`` takes precedence.
+
+Consider the following class that stores the data obtained from an external API
+that uses snake_case property names::
+
+    // src/Api/Payload.php
+    namespace App\Api;
+
+    class Payload
+    {
+        public string $product_name = '';
+        public float $price_amount = 0.0;
+    }
+
+In your application, classes use camelCase for property names, so you can map
+them as follows::
+
+    // src/Entity/Product.php
+    namespace App\Entity;
+
+    use App\Api\Payload;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    // define that Product can be mapped from Payload
+    #[Map(source: Payload::class)]
+    class Product
+    {
+        // define where 'name' should get its value from in the Payload source
+        #[Map(source: 'product_name')]
+        public string $name = '';
+
+        // define where 'price' should get its value from
+        #[Map(source: 'price_amount')]
+        public float $price = 0.0;
+    }
+
+Using it in practice::
+
+    $payload = new Payload();
+    $payload->product_name = 'Super Widget';
+    $payload->price_amount = 123.45;
+
+    $mapper = new ObjectMapper();
+    // map from the payload to the Product class
+    $product = $mapper->map($payload, Product::class);
+
+    // $product->name = 'Super Widget'
+    // $product->price = 123.45
+
+When using source-based mapping, the ``ObjectMapper`` will automatically use the
+target's ``#[Map(source: ...)]`` attributes if no mapping is defined on the
+source class.
+
+Handling Recursion
+------------------
+
+The ObjectMapper automatically detects and handles recursive relationships between
+objects (e.g., a ``User`` has a ``manager`` which is another ``User``, who might
+manage the first user). When it encounters previously mapped objects in the graph,
+it reuses the corresponding target instances to prevent infinite loops::
+
+    // src/Entity/User.php
+    namespace App\Entity;
+
+    use App\Dto\UserDto;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(target: UserDto::class)]
+    class User
+    {
+        public string $name = '';
+        public ?User $manager = null;
+    }
+
+The target DTO object defines the ``User`` class as its source and the
+ObjectMapper component detects the cyclic reference::
+
+    // src/Dto/UserDto.php
+    namespace App\Dto;
+
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+
+    #[Map(source: \App\Entity\User::class)] // can also define mapping here
+    class UserDto
+    {
+        public string $name = '';
+        public ?UserDto $manager = null;
+    }
+
+Using it in practice::
+
+    $manager = new User();
+    $manager->name = 'Alice';
+    $employee = new User();
+    $employee->name = 'Bob';
+    $employee->manager = $manager;
+    // manager's manager is the employee:
+    $manager->manager = $employee;
+
+    $mapper = new ObjectMapper();
+    $employeeDto = $mapper->map($employee, UserDto::class);
+
+    // recursion is handled correctly:
+    // $employeeDto->name === 'Bob'
+    // $employeeDto->manager->name === 'Alice'
+    // $employeeDto->manager->manager === $employeeDto
+
+.. _objectmapper-custom-mapping-logic:
+
+Custom Mapping Logic
+--------------------
+
+For very complex mapping scenarios or if you prefer separating mapping rules from
+your DTOs/Entities, you can implement a custom mapping strategy using the
+:class:`Symfony\\Component\\ObjectMapper\\Metadata\\ObjectMapperMetadataFactoryInterface`.
+This allows defining mapping rules within dedicated mapper services, similar
+to the approach used by libraries like MapStruct in the Java ecosystem.
+
+First, create your custom metadata factory. The following example reads mapping
+rules defined via ``#[Map]`` attributes on a dedicated mapper service class,
+specifically on its ``map`` method for property mappings and on the class itself
+for the source-to-target relationship::
+
+    namespace App\ObjectMapper\Metadata;
+
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+    use Symfony\Component\ObjectMapper\Metadata\Mapping;
+    use Symfony\Component\ObjectMapper\Metadata\ObjectMapperMetadataFactoryInterface;
+    use Symfony\Component\ObjectMapper\ObjectMapperInterface;
+
+    /**
+     * A Metadata factory that implements basics similar to MapStruct.
+     * Reads mapping configuration from attributes on a dedicated mapper service.
+     */
+    final class MapStructMapperMetadataFactory implements ObjectMapperMetadataFactoryInterface
+    {
+        /**
+         * @param class-string<ObjectMapperInterface> $mapperClass The FQCN of the mapper service class
+         */
+        public function __construct(private readonly string $mapperClass)
+        {
+            if (!is_a($this->mapperClass, ObjectMapperInterface::class, true)) {
+                throw new \RuntimeException(sprintf('Mapper class "%s" must implement "%s".', $this->mapperClass, ObjectMapperInterface::class));
+            }
+        }
+
+        public function create(object $object, ?string $property = null, array $context = []): array
+        {
+            try {
+                $refl = new \ReflectionClass($this->mapperClass);
+            } catch (\ReflectionException $e) {
+                throw new \RuntimeException("Failed to reflect mapper class: " . $e->getMessage(), 0, $e);
+            }
+
+            $mapConfigs = [];
+            $sourceIdentifier = $property ?? $object::class;
+
+            // read attributes from the map method (for property mapping) or the class (for class mapping)
+            $attributesSource = $property ? $refl->getMethod('map') : $refl;
+            foreach ($attributesSource->getAttributes(Map::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
+                $map = $attribute->newInstance();
+
+                // check if the attribute's source matches the current property or source class
+                if ($map->source === $sourceIdentifier) {
+                    $mapConfigs[] = new Mapping($map->target, $map->source, $map->if, $map->transform);
+                }
+            }
+
+            // if it's a property lookup and no specific mapping was found, map to the same property
+            if ($property && empty($mapConfigs)) {
+                $mapConfigs[] = new Mapping(target: $property, source: $property);
+            }
+
+            return $mapConfigs;
+        }
+    }
+
+Next, define your mapper service class. This class implements ``ObjectMapperInterface``
+but typically delegates the actual mapping back to a standard ``ObjectMapper``
+instance configured with the custom metadata factory. Mapping rules are defined
+using ``#[Map]`` attributes on this class and its ``map`` method::
+
+    namespace App\ObjectMapper;
+
+    use App\Dto\LegacyUser;
+    use App\Dto\UserDto;
+    use App\ObjectMapper\Metadata\MapStructMapperMetadataFactory;
+    use Symfony\Component\ObjectMapper\Attribute\Map;
+    use Symfony\Component\ObjectMapper\ObjectMapper;
+    use Symfony\Component\ObjectMapper\ObjectMapperInterface;
+
+    // define the source-to-target mapping at the class level
+    #[Map(source: LegacyUser::class, target: UserDto::class)]
+    class LegacyUserMapper implements ObjectMapperInterface
+    {
+        private readonly ObjectMapperInterface $objectMapper;
+
+        // inject the standard ObjectMapper or necessary dependencies
+        public function __construct(?ObjectMapperInterface $objectMapper = null)
+        {
+            // create an ObjectMapper instance configured with *this* mapper's rules
+            $metadataFactory = new MapStructMapperMetadataFactory(self::class);
+            $this->objectMapper = $objectMapper ?? new ObjectMapper($metadataFactory);
+        }
+
+        // define property-specific mapping rules on the map method
+        #[Map(source: 'fullName', target: 'name')] // Map LegacyUser::fullName to UserDto::name
+        #[Map(source: 'creationTimestamp', target: 'registeredAt', transform: [\DateTimeImmutable::class, 'createFromFormat'])]
+        #[Map(source: 'status', if: false)] // Ignore the 'status' property from LegacyUser
+        public function map(object $source, object|string|null $target = null): object
+        {
+            // delegate the actual mapping to the configured ObjectMapper
+            return $this->objectMapper->map($source, $target);
+        }
+    }
+
+Finally, use your custom mapper service::
+
+    use App\Dto\LegacyUser;
+    use App\ObjectMapper\LegacyUserMapper;
+
+    $legacyUser = new LegacyUser();
+    $legacyUser->fullName = 'Jane Doe';
+    $legacyUser->status = 'active'; // this will be ignored
+
+    // instantiate your custom mapper service
+    $mapperService = new LegacyUserMapper();
+
+    // use the map method of your service
+    $userDto = $mapperService->map($legacyUser); // Target (UserDto) is inferred from #[Map] on LegacyUserMapper
+
+This approach keeps mapping logic centralized within dedicated services, which can
+be beneficial for complex applications or when adhering to specific architectural patterns.
+
+Advanced Configuration
+----------------------
+
+The ``ObjectMapper`` constructor accepts optional arguments for advanced usage:
+
+* ``ObjectMapperMetadataFactoryInterface $metadataFactory``: Allows custom metadata
+  factories, such as the one shown in :ref:`the MapStruct-like example <objectmapper-custom-mapping-logic>`.
+  The default is :class:`Symfony\\Component\\ObjectMapper\\Metadata\\ReflectionObjectMapperMetadataFactory`,
+  which uses ``#[Map]`` attributes from source and target classes.
+* ``?PropertyAccessorInterface $propertyAccessor``: Lets you customize how
+  properties are read and written to the target object, useful for accessing
+  private properties or using getters/setters.
+* ``?ContainerInterface $transformCallableLocator``: A PSR-11 container (service locator)
+  that resolves service IDs referenced by the ``transform`` option in ``#[Map]``.
+* ``?ContainerInterface $conditionCallableLocator``: A PSR-11 container for resolving
+  service IDs used in ``if`` conditions within ``#[Map]``.
+
+These dependencies are automatically configured when you use the
+``ObjectMapperInterface`` service provided by Symfony.
diff --git a/page_creation.rst b/page_creation.rst
index 3315dff279d..0e2fd78e180 100644
--- a/page_creation.rst
+++ b/page_creation.rst
@@ -18,7 +18,7 @@ two-step process:
 .. admonition:: Screencast
     :class: screencast
 
-    Do you prefer video tutorials? Check out the `Harmonious Development with Symfony`_
+    Do you prefer video tutorials? Check out the `Cosmic Coding with Symfony`_
     screencast series.
 
 .. seealso::
@@ -302,5 +302,5 @@ Go Deeper with HTTP & Framework Fundamentals
 
 .. _`Twig`: https://twig.symfony.com
 .. _`Composer`: https://getcomposer.org
-.. _`Harmonious Development with Symfony`: https://symfonycasts.com/screencast/symfony/setup
+.. _`Cosmic Coding with Symfony`: https://symfonycasts.com/screencast/symfony/setup
 .. _`attributes`: https://www.php.net/manual/en/language.attributes.overview.php
diff --git a/performance.rst b/performance.rst
index 748bbab7ba7..828333f338b 100644
--- a/performance.rst
+++ b/performance.rst
@@ -263,10 +263,6 @@ in performance, you can stop generating the file as follows:
         // ...
         $container->parameters()->set('debug.container.dump', false);
 
-.. versionadded:: 6.3
-
-    The ``debug.container.dump`` option was introduced in Symfony 6.3.
-
 .. _profiling-applications:
 
 Profiling Symfony Applications
@@ -366,6 +362,13 @@ method does, which stops an event and then restarts it immediately::
     // Lap information is stored as "periods" within the event:
     // $event->getPeriods();
 
+    // Gets the last event period:
+    // $event->getLastPeriod();
+
+.. versionadded:: 7.2
+
+    The ``getLastPeriod()`` method was introduced in Symfony 7.2.
+
 Profiling Sections
 ..................
 
@@ -386,10 +389,16 @@ All events that don't belong to any named section are added to the special secti
 called ``__root__``. This way you can get all stopwatch events, even if you don't
 know their names, as follows::
 
-    foreach($this->stopwatch->getSectionEvents('__root__') as $event) {
+    use Symfony\Component\Stopwatch\Stopwatch;
+
+    foreach($this->stopwatch->getSectionEvents(Stopwatch::ROOT) as $event) {
         echo (string) $event;
     }
 
+.. versionadded:: 7.2
+
+    The ``Stopwatch::ROOT`` constant as a shortcut for ``__root__`` was introduced in Symfony 7.2.
+
 Learn more
 ----------
 
diff --git a/profiler.rst b/profiler.rst
index 1cdf3e57867..7fc97c8ee33 100644
--- a/profiler.rst
+++ b/profiler.rst
@@ -35,10 +35,6 @@ Symfony Profiler, which will look like this:
     in the ``X-Debug-Token-Link`` HTTP response header. Browse the ``/_profiler``
     URL to see all profiles.
 
-.. versionadded:: 6.3
-
-    Profile garbage collection was introduced in Symfony 6.3.
-
 .. note::
 
     To limit the storage used by profiles on disk, they are probabilistically
@@ -97,10 +93,6 @@ look for tokens based on some criteria::
     // gets the latest 10 tokens for requests that happened between 2 and 4 days ago
     $tokens = $profiler->find('', '', 10, '', '4 days ago', '2 days ago');
 
-.. versionadded:: 6.4
-
-    Prefixing the URL filter with a ``!`` symbol to negate the query was introduced in Symfony 6.4.
-
 Data Collectors
 ---------------
 
@@ -225,9 +217,48 @@ user by dynamically rewriting the current page rather than loading entire new
 pages from a server.
 
 By default, the debug toolbar displays the information of the initial page load
-and doesn't refresh after each AJAX request. However, you can set the
-``Symfony-Debug-Toolbar-Replace`` header to a value of ``'1'`` in the response to
-the AJAX request to force the refresh of the toolbar::
+and doesn't refresh after each AJAX request. However, you can configure the
+toolbar to be refreshed after each AJAX request by enabling ``ajax_replace`` in the
+``web_profiler`` configuration:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/web_profiler.yaml
+        web_profiler:
+            toolbar:
+                ajax_replace: true
+
+    .. code-block:: xml
+
+        <!-- config/packages/web_profiler.xml -->
+        <?xml version="1.0" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xmlns:web-profiler="http://symfony.com/schema/dic/webprofiler"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+                <web-profiler:config>
+                    <web-profiler:toolbar ajax-replace="true"/>
+                </web-profiler:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/web_profiler.php
+        use Symfony\Config\WebProfilerConfig;
+
+        return static function (WebProfilerConfig $profiler): void {
+            $profiler->toolbar()
+                ->ajaxReplace(true);
+        };
+
+If you need a more sophisticated solution, you can set the
+``Symfony-Debug-Toolbar-Replace`` header to a value of ``'1'`` in the response
+yourself::
 
     $response->headers->set('Symfony-Debug-Toolbar-Replace', '1');
 
@@ -236,31 +267,21 @@ production. To do that, create an :doc:`event subscriber </event_dispatcher>`
 and listen to the :ref:`kernel.response <component-http-kernel-kernel-response>`
 event::
 
+    use Symfony\Component\DependencyInjection\Attribute\When;
     use Symfony\Component\EventDispatcher\EventSubscriberInterface;
     use Symfony\Component\HttpKernel\Event\ResponseEvent;
     use Symfony\Component\HttpKernel\KernelInterface;
 
     // ...
 
+    #[When(env: 'dev')]
     class MySubscriber implements EventSubscriberInterface
     {
-        public function __construct(
-            private KernelInterface $kernel,
-        ) {
-        }
-
         // ...
 
         public function onKernelResponse(ResponseEvent $event): void
         {
-            if (!$this->kernel->isDebug()) {
-                return;
-            }
-
-            $request = $event->getRequest();
-            if (!$request->isXmlHttpRequest()) {
-                return;
-            }
+            // Your custom logic here
 
             $response = $event->getResponse();
             $response->headers->set('Symfony-Debug-Toolbar-Replace', '1');
diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst
index a323461885d..3b66570b3d3 100644
--- a/quick_tour/the_architecture.rst
+++ b/quick_tour/the_architecture.rst
@@ -159,29 +159,22 @@ Twig Extension & Autoconfiguration
 Thanks to Symfony's service handling, you can *extend* Symfony in many ways, like
 by creating an event subscriber or a security voter for complex authorization
 rules. Let's add a new filter to Twig called ``greet``. How? Create a class
-that extends ``AbstractExtension``::
+with your logic::
 
     // src/Twig/GreetExtension.php
     namespace App\Twig;
 
     use App\GreetingGenerator;
-    use Twig\Extension\AbstractExtension;
-    use Twig\TwigFilter;
+    use Twig\Attribute\AsTwigFilter;
 
-    class GreetExtension extends AbstractExtension
+    class GreetExtension
     {
         public function __construct(
             private GreetingGenerator $greetingGenerator,
         ) {
         }
 
-        public function getFilters(): array
-        {
-            return [
-                new TwigFilter('greet', [$this, 'greetUser']),
-            ];
-        }
-
+        #[AsTwigFilter('greet')]
         public function greetUser(string $name): string
         {
             $greeting =  $this->greetingGenerator->getRandomGreeting();
@@ -198,7 +191,7 @@ After creating just *one* file, you can use this immediately:
     {# Will print something like "Hey Symfony!" #}
     <h1>{{ name|greet }}</h1>
 
-How does this work? Symfony notices that your class extends ``AbstractExtension``
+How does this work? Symfony notices that your class uses the ``#[AsTwigFilter]`` attribute
 and so *automatically* registers it as a Twig extension. This is called autoconfiguration,
 and it works for *many* many things. Create a class and then extend a base class
 (or implement an interface). Symfony takes care of the rest.
diff --git a/rate_limiter.rst b/rate_limiter.rst
index a53f679f1c8..5fd453f0534 100644
--- a/rate_limiter.rst
+++ b/rate_limiter.rst
@@ -216,9 +216,26 @@ at a rate of another 500 requests every 15 minutes. If you don't make that
 number of requests, the unused ones don't accumulate (the ``limit`` option
 prevents that number from being higher than 5,000).
 
+.. tip::
+
+    All rate-limiters are tagged with the ``rate_limiter`` tag, so you can
+    find them with a :doc:`tagged iterator </service_container/tags>` or
+    :doc:`locator </service_container/service_subscribers_locators>`.
+
+    .. versionadded:: 7.1
+
+        The automatic addition of the ``rate_limiter`` tag was introduced
+        in Symfony 7.1.
+
 Rate Limiting in Action
 -----------------------
 
+.. versionadded:: 7.3
+
+    :class:`Symfony\\Component\\RateLimiter\\RateLimiterFactoryInterface` was
+    added and should now be used for autowiring instead of
+    :class:`Symfony\\Component\\RateLimiter\\RateLimiterFactory`.
+
 After having installed and configured the rate limiter, inject it in any service
 or controller and call the ``consume()`` method to try to consume a given number
 of tokens. For example, this controller uses the previous rate limiter to control
@@ -231,13 +248,13 @@ the number of requests to the API::
     use Symfony\Component\HttpFoundation\Request;
     use Symfony\Component\HttpFoundation\Response;
     use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
-    use Symfony\Component\RateLimiter\RateLimiterFactory;
+    use Symfony\Component\RateLimiter\RateLimiterFactoryInterface;
 
     class ApiController extends AbstractController
     {
         // if you're using service autowiring, the variable name must be:
         // "rate limiter name" (in camelCase) + "Limiter" suffix
-        public function index(Request $request, RateLimiterFactory $anonymousApiLimiter): Response
+        public function index(Request $request, RateLimiterFactoryInterface $anonymousApiLimiter): Response
         {
             // create a limiter based on a unique identifier of the client
             // (e.g. the client's IP address, a username/email, an API key, etc.)
@@ -280,11 +297,11 @@ using the ``reserve()`` method::
     use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
     use Symfony\Component\HttpFoundation\Request;
     use Symfony\Component\HttpFoundation\Response;
-    use Symfony\Component\RateLimiter\RateLimiterFactory;
+    use Symfony\Component\RateLimiter\RateLimiterFactoryInterface;
 
     class ApiController extends AbstractController
     {
-        public function registerUser(Request $request, RateLimiterFactory $authenticatedApiLimiter): Response
+        public function registerUser(Request $request, RateLimiterFactoryInterface $authenticatedApiLimiter): Response
         {
             $apiKey = $request->headers->get('apikey');
             $limiter = $authenticatedApiLimiter->create($apiKey);
@@ -321,11 +338,6 @@ processes by reserving unused tokens.
             $limit->wait();
         } while (!$limit->isAccepted());
 
-.. versionadded:: 6.4
-
-    The support for the ``reserve()`` method for the ``SlidingWindow`` strategy
-    was introduced in Symfony 6.4.
-
 Exposing the Rate Limiter Status
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -344,11 +356,11 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the
     use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
     use Symfony\Component\HttpFoundation\Request;
     use Symfony\Component\HttpFoundation\Response;
-    use Symfony\Component\RateLimiter\RateLimiterFactory;
+    use Symfony\Component\RateLimiter\RateLimiterFactoryInterface;
 
     class ApiController extends AbstractController
     {
-        public function index(Request $request, RateLimiterFactory $anonymousApiLimiter): Response
+        public function index(Request $request, RateLimiterFactoryInterface $anonymousApiLimiter): Response
         {
             $limiter = $anonymousApiLimiter->create($request->getClientIp());
             $limit = $limiter->consume();
@@ -371,19 +383,6 @@ the :class:`Symfony\\Component\\RateLimiter\\Reservation` object returned by the
         }
     }
 
-.. versionadded:: 6.4
-
-    The :method:`Symfony\\Component\\RateLimiter\\Policy\\SlidingWindow::calculateTimeForTokens`
-    method was introduced in Symfony 6.4.
-
-.. deprecated:: 6.4
-
-    The :method:`Symfony\\Component\\RateLimiter\\Policy\\SlidingWindow::getRetryAfter`
-    method is deprecated since Symfony 6.4. Prior to this version, the
-    ``getRetryAfter()`` method must be used instead of the
-    :method:`Symfony\\Component\\RateLimiter\\Policy\\SlidingWindow::calculateTimeForTokens`
-    method.
-
 .. _rate-limiter-storage:
 
 Storing Rate Limiter State
@@ -468,9 +467,10 @@ simultaneous requests (e.g. three servers of a company hitting your API at the
 same time). Rate limiters use :doc:`locks </lock>` to protect their operations
 against these race conditions.
 
-By default, Symfony uses the global lock configured by ``framework.lock``, but
-you can use a specific :ref:`named lock <lock-named-locks>` via the
-``lock_factory`` option (or none at all):
+By default, if the :doc:`lock </lock>` component is installed, Symfony uses the
+global lock configured by ``framework.lock``, but you can use a specific
+:ref:`named lock <lock-named-locks>` via the ``lock_factory`` option (or none
+at all):
 
 .. configuration-block::
 
@@ -541,6 +541,129 @@ you can use a specific :ref:`named lock <lock-named-locks>` via the
                 ;
         };
 
+.. versionadded:: 7.3
+
+    Before Symfony 7.3, configuring a rate limiter and using the default configured
+    lock factory (``lock.factory``) failed if the Symfony Lock component was not
+    installed in the application.
+
+Compound Rate Limiter
+---------------------
+
+.. versionadded:: 7.3
+
+    Support for configuring compound rate limiters was introduced in Symfony 7.3.
+
+You can configure multiple rate limiters to work together:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/rate_limiter.yaml
+        framework:
+            rate_limiter:
+                two_per_minute:
+                    policy: 'fixed_window'
+                    limit: 2
+                    interval: '1 minute'
+                five_per_hour:
+                    policy: 'fixed_window'
+                    limit: 5
+                    interval: '1 hour'
+                contact_form:
+                    policy: 'compound'
+                    limiters: [two_per_minute, five_per_hour]
+
+    .. code-block:: xml
+
+        <!-- config/packages/rate_limiter.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony
+                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:rate-limiter>
+                    <framework:limiter name="two_per_minute"
+                        policy="fixed_window"
+                        limit="2"
+                        interval="1 minute"
+                    />
+
+                    <framework:limiter name="five_per_hour"
+                        policy="fixed_window"
+                        limit="5"
+                        interval="1 hour"
+                    />
+
+                    <framework:limiter name="contact_form"
+                        policy="compound"
+                    >
+                        <limiter>two_per_minute</limiter>
+                        <limiter>five_per_hour</limiter>
+                    </framework:limiter>
+                </framework:rate-limiter>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/rate_limiter.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->rateLimiter()
+                ->limiter('two_per_minute')
+                    ->policy('fixed_window')
+                    ->limit(2)
+                    ->interval('1 minute')
+                ;
+
+            $framework->rateLimiter()
+                ->limiter('two_per_minute')
+                    ->policy('fixed_window')
+                    ->limit(5)
+                    ->interval('1 hour')
+                ;
+
+            $framework->rateLimiter()
+                ->limiter('contact_form')
+                    ->policy('compound')
+                    ->limiters(['two_per_minute', 'five_per_hour'])
+                ;
+        };
+
+Then, inject and use as normal::
+
+    // src/Controller/ContactController.php
+    namespace App\Controller;
+
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\HttpFoundation\Request;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\RateLimiter\RateLimiterFactoryInterface;
+
+    class ContactController extends AbstractController
+    {
+        public function registerUser(Request $request, RateLimiterFactoryInterface $contactFormLimiter): Response
+        {
+            $limiter = $contactFormLimiter->create($request->getClientIp());
+
+            if (false === $limiter->consume(1)->isAccepted()) {
+                // either of the two limiters has been reached
+            }
+
+            // ...
+        }
+
+        // ...
+    }
+
 .. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html
 .. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html
 .. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/
diff --git a/reference/attributes.rst b/reference/attributes.rst
index 9ead60b3662..968c7df1568 100644
--- a/reference/attributes.rst
+++ b/reference/attributes.rst
@@ -5,11 +5,6 @@ Attributes are the successor of annotations since PHP 8. Attributes are native
 to the language and Symfony takes full advantage of them across the framework
 and its different components.
 
-.. deprecated:: 6.4
-
-    Annotations across the framework are deprecated since Symfony 6.4, you must
-    only use attributes instead.
-
 Doctrine Bridge
 ~~~~~~~~~~~~~~~
 
@@ -19,7 +14,7 @@ Doctrine Bridge
 Command
 ~~~~~~~
 
-* :ref:`AsCommand <console_registering-the-command>`
+* :ref:`AsCommand <console_creating-command>`
 
 Contracts
 ~~~~~~~~~
@@ -40,12 +35,21 @@ Dependency Injection
 * :doc:`AutowireDecorated </service_container/service_decoration>`
 * :ref:`AutowireIterator <service-locator_autowire-iterator>`
 * :ref:`AutowireLocator <service-locator_autowire-locator>`
+* :ref:`AutowireMethodOf <autowiring_closures>`
 * :ref:`AutowireServiceClosure <autowiring_closures>`
 * :ref:`Exclude <service-psr4-loader>`
+* :ref:`Lazy <lazy-services_configuration>`
 * :ref:`TaggedIterator <tags_reference-tagged-services>`
 * :ref:`TaggedLocator <service-subscribers-locators_defining-service-locator>`
 * :ref:`Target <autowiring-multiple-implementations-same-type>`
 * :ref:`When <service-container_limiting-to-env>`
+* :ref:`WhenNot <service-container_limiting-to-env>`
+
+.. deprecated:: 7.1
+
+    The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator`
+    and :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator`
+    attributes were deprecated in Symfony 7.1.
 
 EventDispatcher
 ~~~~~~~~~~~~~~~
@@ -67,6 +71,7 @@ HttpKernel
 * :ref:`MapQueryParameter <controller_map-request>`
 * :ref:`MapQueryString <controller_map-request>`
 * :ref:`MapRequestPayload <controller_map-request>`
+* :ref:`MapUploadedFile <controller_map-uploaded-file>`
 * :ref:`ValueResolver <managing-value-resolvers>`
 * :ref:`WithHttpStatus <framework_exceptions>`
 * :ref:`WithLogLevel <framework_exceptions>`
@@ -74,6 +79,7 @@ HttpKernel
 Messenger
 ~~~~~~~~~
 
+* :ref:`AsMessage <messenger-message-attribute>`
 * :ref:`AsMessageHandler <messenger-handler>`
 
 RemoteEvent
@@ -97,6 +103,7 @@ Security
 ~~~~~~~~
 
 * :ref:`CurrentUser <security-json-login>`
+* :ref:`IsCsrfTokenValid <csrf-controller-attributes>`
 * :ref:`IsGranted <security-securing-controller-attributes>`
 
 .. _reference-attributes-serializer:
@@ -116,6 +123,9 @@ Twig
 ~~~~
 
 * :ref:`Template <templates-template-attribute>`
+* :ref:`AsTwigFilter <templates-twig-filter-attribute>`
+* :ref:`AsTwigFunction <templates-twig-function-attribute>`
+* ``AsTwigTest``
 
 Symfony UX
 ~~~~~~~~~~
diff --git a/reference/configuration/debug.rst b/reference/configuration/debug.rst
index fb8f49821f1..6ca05b49bd7 100644
--- a/reference/configuration/debug.rst
+++ b/reference/configuration/debug.rst
@@ -17,42 +17,12 @@ key in your application configuration.
     # environment variables with their actual values
     $ php bin/console debug:config --resolve-env debug
 
-.. versionadded:: 6.2
-
-    The ``--resolve-env`` option was introduced in Symfony 6.2.
-
 .. note::
 
     When using XML, you must use the ``http://symfony.com/schema/dic/debug``
     namespace and the related XSD schema is available at:
     ``https://symfony.com/schema/dic/debug/debug-1.0.xsd``
 
-max_items
-~~~~~~~~~
-
-**type**: ``integer`` **default**: ``2500``
-
-This is the maximum number of items to dump. Setting this option to ``-1``
-disables the limit.
-
-min_depth
-~~~~~~~~~
-
-**type**: ``integer`` **default**: ``1``
-
-Configures the minimum tree depth until which all items are guaranteed to
-be cloned. After this depth is reached, only ``max_items`` items will be
-cloned. The default value is ``1``, which is consistent with older Symfony
-versions.
-
-max_string_length
-~~~~~~~~~~~~~~~~~
-
-**type**: ``integer`` **default**: ``-1``
-
-This option configures the maximum string length before truncating the
-string. The default value (``-1``) means that strings are never truncated.
-
 .. _configuration-debug-dump_destination:
 
 dump_destination
@@ -102,3 +72,29 @@ Typically, you would set this to ``php://stderr``:
 
 
 Configure it to ``"tcp://%env(VAR_DUMPER_SERVER)%"`` in order to use the :ref:`ServerDumper feature <var-dumper-dump-server>`.
+
+max_items
+~~~~~~~~~
+
+**type**: ``integer`` **default**: ``2500``
+
+This is the maximum number of items to dump. Setting this option to ``-1``
+disables the limit.
+
+max_string_length
+~~~~~~~~~~~~~~~~~
+
+**type**: ``integer`` **default**: ``-1``
+
+This option configures the maximum string length before truncating the
+string. The default value (``-1``) means that strings are never truncated.
+
+min_depth
+~~~~~~~~~
+
+**type**: ``integer`` **default**: ``1``
+
+Configures the minimum tree depth until which all items are guaranteed to
+be cloned. After this depth is reached, only ``max_items`` items will be
+cloned. The default value is ``1``, which is consistent with older Symfony
+versions.
diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst
index 9b1569622e7..db6336e1ee6 100644
--- a/reference/configuration/doctrine.rst
+++ b/reference/configuration/doctrine.rst
@@ -385,18 +385,14 @@ you can control. The following configuration options exist for a mapping:
 ``type``
 ........
 
-One of ``annotation`` (for PHP annotations; it's the default value),
-``attribute`` (for PHP attributes), ``xml``, ``php`` or
-``staticphp``. This specifies which type of metadata type your mapping uses.
+One of ``attribute`` (for PHP attributes; it's the default value),
+``xml``, ``php`` or ``staticphp``. This specifies which
+type of metadata type your mapping uses.
 
 .. versionadded:: 3.0
 
     The ``yml`` mapping configuration is deprecated and was removed in Doctrine ORM 3.0.
 
-.. deprecated:: 6.4
-
-    Annotations are deprecated since Symfony 6.4, use attributes instead.
-
 See `Doctrine Metadata Drivers`_ for more information about this option.
 
 ``dir``
@@ -602,12 +598,12 @@ set up the connection using environment variables for the certificate paths:
                 server_version: '8.0.31'
                 driver: 'pdo_mysql'
                 options:
-                    # SSL private key (PDO::MYSQL_ATTR_SSL_KEY)
-                    1007: '%env(MYSQL_SSL_KEY)%'
-                    # SSL certificate (PDO::MYSQL_ATTR_SSL_CERT)
-                    1008: '%env(MYSQL_SSL_CERT)%'
-                    # SSL CA authority (PDO::MYSQL_ATTR_SSL_CA)
-                    1009: '%env(MYSQL_SSL_CA)%'
+                    # SSL private key
+                    !php/const 'PDO::MYSQL_ATTR_SSL_KEY': '%env(MYSQL_SSL_KEY)%'
+                    # SSL certificate
+                    !php/const 'PDO::MYSQL_ATTR_SSL_CERT': '%env(MYSQL_SSL_CERT)%'
+                    # SSL CA authority
+                    !php/const 'PDO::MYSQL_ATTR_SSL_CA': '%env(MYSQL_SSL_CA)%'
 
     .. code-block:: xml
 
@@ -626,9 +622,9 @@ set up the connection using environment variables for the certificate paths:
                     server-version="8.0.31"
                     driver="pdo_mysql">
 
-                    <doctrine:option key="1007">%env(MYSQL_SSL_KEY)%</doctrine:option>
-                    <doctrine:option key="1008">%env(MYSQL_SSL_CERT)%</doctrine:option>
-                    <doctrine:option key="1009">%env(MYSQL_SSL_CA)%</doctrine:option>
+                    <doctrine:option key-type="constant" key="PDO::MYSQL_ATTR_SSL_KEY">%env(MYSQL_SSL_KEY)%</doctrine:option>
+                    <doctrine:option key-type="constant" key="PDO::MYSQL_ATTR_SSL_CERT">%env(MYSQL_SSL_CERT)%</doctrine:option>
+                    <doctrine:option key-type="constant" key="PDO::MYSQL_ATTR_SSL_CA">%env(MYSQL_SSL_CA)%</doctrine:option>
                 </doctrine:dbal>
             </doctrine:config>
         </container>
diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst
index 804be569031..e60e5d67c99 100644
--- a/reference/configuration/framework.rst
+++ b/reference/configuration/framework.rst
@@ -19,280 +19,270 @@ configured under the ``framework`` key in your application configuration.
     namespace and the related XSD schema is available at:
     ``https://symfony.com/schema/dic/symfony/symfony-1.0.xsd``
 
-.. _configuration-framework-secret:
-
-secret
-~~~~~~
-
-**type**: ``string`` **required**
-
-This is a string that should be unique to your application and it's commonly
-used to add more entropy to security related operations. Its value should
-be a series of characters, numbers and symbols chosen randomly and the
-recommended length is around 32 characters.
-
-In practice, Symfony uses this value for encrypting the cookies used
-in the :doc:`remember me functionality </security/remember_me>` and for
-creating signed URIs when using :ref:`ESI (Edge Side Includes) <edge-side-includes>`.
-That's why you should treat this value as if it were a sensitive credential and
-**never make it public**.
-
-This option becomes the service container parameter named ``kernel.secret``,
-which you can use whenever the application needs an immutable random string
-to add more entropy.
-
-As with any other security-related parameter, it is a good practice to change
-this value from time to time. However, keep in mind that changing this value
-will invalidate all signed URIs and Remember Me cookies. That's why, after
-changing this value, you should regenerate the application cache and log
-out all the application users.
-
-handle_all_throwables
-~~~~~~~~~~~~~~~~~~~~~
-
-**type**: ``boolean`` **default**: ``false``
-
-If set to ``true``, the Symfony kernel will catch all ``\Throwable`` exceptions
-thrown by the application and will turn them into HTTP responses.
-
-Starting from Symfony 7.0, the default value of this option will be ``true``.
-
-.. versionadded:: 6.2
+annotations
+~~~~~~~~~~~
 
-    The ``handle_all_throwables`` option was introduced in Symfony 6.2.
+.. _reference-annotations-cache:
 
-.. _configuration-framework-http_cache:
+cache
+.....
 
-http_cache
-~~~~~~~~~~
+**type**: ``string`` **default**: ``php_array``
 
-enabled
-.......
+This option can be one of the following values:
 
-**type**: ``boolean`` **default**: ``false``
+php_array
+    Use a PHP array to cache annotations in memory
+file
+    Use the filesystem to cache annotations
+none
+    Disable the caching of annotations
 
 debug
 .....
 
 **type**: ``boolean`` **default**: ``%kernel.debug%``
 
-If true, exceptions are thrown when things go wrong. Otherwise, the cache will
-try to carry on and deliver a meaningful response.
-
-trace_level
-...........
-
-**type**: ``string`` **possible values**: ``'none'``, ``'short'`` or ``'full'``
+Whether to enable debug mode for caching. If enabled, the cache will
+automatically update when the original file is changed (both with code and
+annotation changes). For performance reasons, it is recommended to disable
+debug mode in production, which will happen automatically if you use the
+default value.
 
-For 'short', a concise trace of the main request will be added as an HTTP header.
-'full' will add traces for all requests (including ESI subrequests).
-(default: ``'full'`` if in debug; ``'none'`` otherwise)
+file_cache_dir
+..............
 
-trace_header
-............
+**type**: ``string`` **default**: ``%kernel.cache_dir%/annotations``
 
-**type**: ``string`` **default**: ``'X-Symfony-Cache'``
+The directory to store cache files for annotations, in case
+``annotations.cache`` is set to ``'file'``.
 
-Header name to use for traces.
+.. _reference-assets:
 
-default_ttl
-...........
+assets
+~~~~~~
 
-**type**: ``integer`` **default**: ``0``
+The following options configure the behavior of the
+:ref:`Twig asset() function <reference-twig-function-asset>`.
 
-The number of seconds that a cache entry should be considered fresh when no
-explicit freshness information is provided in a response. Explicit
-Cache-Control or Expires headers override this value.
+.. _reference-assets-base-path:
 
-private_headers
-...............
+base_path
+.........
 
-**type**: ``array``  **default**: ``['Authorization', 'Cookie']``
+**type**: ``string``
 
-Set of request headers that trigger "private" cache-control behavior on responses
-that don't explicitly state whether the response is public or private via a
-Cache-Control directive.
+This option allows you to prepend a base path to the URLs generated for assets:
 
-skip_response_headers
-.....................
+.. configuration-block::
 
-**type**: ``array`` **default**: ``Set-Cookie``
+    .. code-block:: yaml
 
-Set of response headers that will never be cached even when the response is cacheable
-and public.
+        # config/packages/framework.yaml
+        framework:
+            # ...
+            assets:
+                base_path: '/images'
 
-.. versionadded:: 6.3
+    .. code-block:: xml
 
-    The ``skip_response_headers`` option was introduced in Symfony 6.3.
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-allow_reload
-............
+            <framework:config>
+                <framework:assets base-path="/images"/>
+            </framework:config>
+        </container>
 
-**type**: ``boolean`` **default**: ``false``
+    .. code-block:: php
 
-Specifies whether the client can force a cache reload by including a
-Cache-Control "no-cache" directive in the request. Set it to ``true``
-for compliance with RFC 2616.
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
 
-allow_revalidate
-................
+        return static function (FrameworkConfig $framework): void {
+            // ...
+            $framework->assets()
+                ->basePath('/images');
+        };
 
-**type**: ``boolean`` **default**: ``false``
+With this configuration, a call to ``asset('logo.png')`` will generate
+``/images/logo.png`` instead of ``/logo.png``.
 
-Specifies whether the client can force a cache revalidate by including a
-Cache-Control "max-age=0" directive in the request. Set it to ``true``
-for compliance with RFC 2616.
+.. _reference-templating-base-urls:
+.. _reference-assets-base-urls:
 
-stale_while_revalidate
-......................
+base_urls
+.........
 
-**type**: ``integer`` **default**: ``2``
+**type**: ``array``
 
-Specifies the default number of seconds (the granularity is the second as the
-Response TTL precision is a second) during which the cache can immediately return
-a stale response while it revalidates it in the background.
-This setting is overridden by the stale-while-revalidate HTTP Cache-Control
-extension (see RFC 5861).
+This option allows you to define base URLs to be used for assets.
+If multiple base URLs are provided, Symfony will select one from the
+collection each time it generates an asset's path:
 
-stale_if_error
-..............
+.. configuration-block::
 
-**type**: ``integer`` **default**: ``60``
+    .. code-block:: yaml
 
-Specifies the default number of seconds (the granularity is the second) during
-which the cache can serve a stale response when an error is encountered.
-This setting is overridden by the stale-if-error HTTP
-Cache-Control extension (see RFC 5861).
+        # config/packages/framework.yaml
+        framework:
+            # ...
+            assets:
+                base_urls:
+                    - 'http://cdn.example.com/'
 
-terminate_on_cache_hit
-......................
+    .. code-block:: xml
 
-**type**: ``boolean`` **default**: ``true``
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-If ``true``, the :ref:`kernel.terminate <component-http-kernel-kernel-terminate>`
-event is dispatched even when the cache is hit.
+            <framework:config>
+                <framework:assets base-url="http://cdn.example.com/"/>
+            </framework:config>
+        </container>
 
-Unless your application needs to process events on cache hits, it's recommended
-to set this to ``false`` to improve performance, because it avoids having to
-bootstrap the Symfony framework on a cache hit.
+    .. code-block:: php
 
-.. versionadded:: 6.2
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
 
-    The ``terminate_on_cache_hit`` option was introduced in Symfony 6.2.
+        return static function (FrameworkConfig $framework): void {
+            // ...
+            $framework->assets()
+                ->baseUrls(['http://cdn.example.com/']);
+        };
 
-.. deprecated:: 6.2
+.. _reference-assets-json-manifest-path:
+.. _reference-templating-json-manifest-path:
 
-    Setting the ``terminate_on_cache_hit`` option to ``true`` was deprecated in
-    Symfony 6.2 and the option will be removed in Symfony 7.0.
+json_manifest_path
+..................
 
- .. _configuration-framework-http_method_override:
+**type**: ``string`` **default**: ``null``
 
-http_method_override
-~~~~~~~~~~~~~~~~~~~~
+The file path or absolute URL to a ``manifest.json`` file containing an
+associative array of asset names and their respective compiled names. A common
+cache-busting technique using a "manifest" file works by writing out assets with
+a "hash" appended to their file names (e.g. ``main.ae433f1cb.css``) during a
+front-end compilation routine.
 
-**type**: ``boolean`` **default**: (see explanation below)
+.. tip::
 
-This determines whether the ``_method`` request parameter is used as the
-intended HTTP method on POST requests. If enabled, the
-:method:`Request::enableHttpMethodParameterOverride <Symfony\\Component\\HttpFoundation\\Request::enableHttpMethodParameterOverride>`
-method gets called automatically. It becomes the service container parameter
-named ``kernel.http_method_override``.
+    Symfony's :ref:`Webpack Encore <frontend-webpack-encore>` supports
+    :ref:`outputting hashed assets <encore-long-term-caching>`. Moreover, this
+    can be incorporated into many other workflows, including Webpack and
+    Gulp using `webpack-manifest-plugin`_ and `gulp-rev`_, respectively.
 
-The **default value** is:
+This option can be set globally for all assets and individually for each asset
+package:
 
-* ``true``, if you have an existing application that you've upgraded from an older
-  Symfony version without resyncing the :doc:`Symfony Flex </setup/flex>` recipes;
-* ``false``, if you've created a new Symfony application or updated the Symfony
-  Flex recipes. This is also the default value starting from Symfony 7.0.
+.. configuration-block::
 
-.. deprecated:: 6.1
+    .. code-block:: yaml
 
-    Not setting a value explicitly for this option is deprecated since Symfony 6.1
-    because the default value will change to ``false`` in Symfony 7.0.
+        # config/packages/framework.yaml
+        framework:
+            assets:
+                # this manifest is applied to every asset (including packages)
+                json_manifest_path: "%kernel.project_dir%/public/build/manifest.json"
+                # you can use absolute URLs too and Symfony will download them automatically
+                # json_manifest_path: 'https://cdn.example.com/manifest.json'
+                packages:
+                    foo_package:
+                        # this package uses its own manifest (the default file is ignored)
+                        json_manifest_path: "%kernel.project_dir%/public/build/a_different_manifest.json"
+                        # Throws an exception when an asset is not found in the manifest
+                        strict_mode: %kernel.debug%
+                    bar_package:
+                        # this package uses the global manifest (the default file is used)
+                        base_path: '/images'
 
-.. seealso::
+    .. code-block:: xml
 
-    :ref:`Changing the Action and HTTP Method <forms-change-action-method>` of
-    Symfony forms.
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-.. warning::
-
-    If you're using the :ref:`HttpCache Reverse Proxy <symfony2-reverse-proxy>`
-    with this option, the kernel will ignore the ``_method`` parameter,
-    which could lead to errors.
-
-    To fix this, invoke the ``enableHttpMethodParameterOverride()`` method
-    before creating the ``Request`` object::
-
-        // public/index.php
-
-        // ...
-        $kernel = new CacheKernel($kernel);
-
-        Request::enableHttpMethodParameterOverride(); // <-- add this line
-        $request = Request::createFromGlobals();
-        // ...
-
-trust_x_sendfile_type_header
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-**type**: ``boolean`` **default**: ``false``
-
-.. versionadded:: 6.1
-
-    The ``trust_x_sendfile_type_header`` option was introduced in Symfony 6.1.
-
-``X-Sendfile`` is a special HTTP header that tells web servers to replace the
-response contents by the file that is defined in that header. This improves
-performance because files are no longer served by your application but directly
-by the web server.
+            <framework:config>
+                <!-- this manifest is applied to every asset (including packages) -->
+                <framework:assets json-manifest-path="%kernel.project_dir%/public/build/manifest.json">
+                <!-- you can use absolute URLs too and Symfony will download them automatically -->
+                <!-- <framework:assets json-manifest-path="https://cdn.example.com/manifest.json"> -->
+                    <!-- this package uses its own manifest (the default file is ignored) -->
+                    <!-- Throws an exception when an asset is not found in the manifest -->
+                    <framework:package
+                        name="foo_package"
+                        json-manifest-path="%kernel.project_dir%/public/build/a_different_manifest.json" strict-mode="%kernel.debug%"/>
+                    <!-- this package uses the global manifest (the default file is used) -->
+                    <framework:package
+                        name="bar_package"
+                        base-path="/images"/>
+                </framework:assets>
+            </framework:config>
+        </container>
 
-This configuration option determines whether to trust ``x-sendfile`` header for
-BinaryFileResponse. If enabled, Symfony calls the
-:method:`BinaryFileResponse::trustXSendfileTypeHeader <Symfony\\Component\\HttpFoundation\\BinaryFileResponse::trustXSendfileTypeHeader>`
-method automatically. It becomes the service container parameter named
-``kernel.trust_x_sendfile_type_header``.
+    .. code-block:: php
 
-.. _reference-framework-trusted-headers:
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
 
-trusted_headers
-~~~~~~~~~~~~~~~
+        return static function (FrameworkConfig $framework): void {
+            // ...
+            $framework->assets()
+                // this manifest is applied to every asset (including packages)
+                ->jsonManifestPath('%kernel.project_dir%/public/build/manifest.json');
 
-The ``trusted_headers`` option is needed to configure which client information
-should be trusted (e.g. their host) when running Symfony behind a load balancer
-or a reverse proxy. See :doc:`/deployment/proxies`.
+            // you can use absolute URLs too and Symfony will download them automatically
+            // 'json_manifest_path' => 'https://cdn.example.com/manifest.json',
+            $framework->assets()->package('foo_package')
+                // this package uses its own manifest (the default file is ignored)
+                ->jsonManifestPath('%kernel.project_dir%/public/build/a_different_manifest.json')
+                // Throws an exception when an asset is not found in the manifest
+                ->setStrictMode('%kernel.debug%');
 
-.. _reference-framework-trusted-proxies:
+            $framework->assets()->package('bar_package')
+                // this package uses the global manifest (the default file is used)
+                ->basePath('/images');
+        };
 
-trusted_proxies
-~~~~~~~~~~~~~~~
+.. note::
 
-The ``trusted_proxies`` option is needed to get precise information about the
-client (e.g. their IP address) when running Symfony behind a load balancer or a
-reverse proxy. See :doc:`/deployment/proxies`.
+    This parameter cannot be set at the same time as ``version`` or ``version_strategy``.
+    Additionally, this option cannot be nullified at the package scope if a global manifest
+    file is specified.
 
-.. _reference-framework-ide:
+.. tip::
 
-ide
-~~~
+    If you request an asset that is *not found* in the ``manifest.json`` file, the original -
+    *unmodified* - asset path will be returned.
+    You can set ``strict_mode`` to ``true`` to get an exception when an asset is *not found*.
 
-**type**: ``string`` **default**: ``%env(default::SYMFONY_IDE)%``
+.. note::
 
-Symfony turns file paths seen in variable dumps and exception messages into
-links that open those files right inside your browser. If you prefer to open
-those files in your favorite IDE or text editor, set this option to any of the
-following values: ``phpstorm``, ``sublime``, ``textmate``, ``macvim``, ``emacs``,
-``atom`` and ``vscode``.
+    If a URL is set, the JSON manifest is downloaded on each request using the `http_client`_.
 
-.. note::
+.. _reference-framework-assets-packages:
 
-    The ``phpstorm`` option is supported natively by PhpStorm on macOS and
-    Windows; Linux requires installing `phpstorm-url-handler`_.
+packages
+........
 
-If you use another editor, the expected configuration value is a URL template
-that contains an ``%f`` placeholder where the file path is expected and ``%l``
-placeholder for the line number (percentage signs (``%``) must be escaped by
-doubling them to prevent Symfony from interpreting them as container parameters).
+You can group assets into packages, to specify different base URLs for them:
 
 .. configuration-block::
 
@@ -300,7 +290,11 @@ doubling them to prevent Symfony from interpreting them as container parameters)
 
         # config/packages/framework.yaml
         framework:
-            ide: 'myide://open?url=file://%%f&line=%%l'
+            # ...
+            assets:
+                packages:
+                    avatars:
+                        base_urls: 'http://static_cdn.example.com/avatars'
 
     .. code-block:: xml
 
@@ -313,7 +307,13 @@ doubling them to prevent Symfony from interpreting them as container parameters)
                 https://symfony.com/schema/dic/services/services-1.0.xsd
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-            <framework:config ide="myide://open?url=file://%%f&line=%%l"/>
+            <framework:config>
+                <framework:assets>
+                    <framework:package
+                        name="avatars"
+                        base-url="http://static_cdn.example.com/avatars"/>
+                </framework:assets>
+            </framework:config>
         </container>
 
     .. code-block:: php
@@ -322,118 +322,74 @@ doubling them to prevent Symfony from interpreting them as container parameters)
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->ide('myide://open?url=file://%%f&line=%%l');
+            // ...
+            $framework->assets()
+                ->package('avatars')
+                    ->baseUrls(['http://static_cdn.example.com/avatars']);
         };
 
-Since every developer uses a different IDE, the recommended way to enable this
-feature is to configure it on a system level. First, you can define this option
-in the ``SYMFONY_IDE`` environment variable, which Symfony reads automatically
-when ``framework.ide`` config is not set.
-
-.. versionadded:: 6.1
-
-    ``SYMFONY_IDE`` environment variable support was introduced in Symfony 6.1.
-
-Another alternative is to set the ``xdebug.file_link_format`` option in your
-``php.ini`` configuration file. The format to use is the same as for the
-``framework.ide`` option, but without the need to escape the percent signs
-(``%``) by doubling them:
-
-.. code-block:: ini
-
-    // example for PhpStorm
-    xdebug.file_link_format="phpstorm://open?file=%f&line=%l"
-
-    // example for PhpStorm with Jetbrains Toolbox
-    xdebug.file_link_format="jetbrains://phpstorm/navigate/reference?project=example&path=%f:%l"
-
-    // example for Sublime Text
-    xdebug.file_link_format="subl://open?url=file://%f&line=%l"
-
-.. note::
-
-    If both ``framework.ide`` and ``xdebug.file_link_format`` are defined,
-    Symfony uses the value of the ``xdebug.file_link_format`` option.
-
-.. tip::
-
-    Setting the ``xdebug.file_link_format`` ini option works even if the Xdebug
-    extension is not enabled.
-
-.. tip::
-
-    When running your app in a container or in a virtual machine, you can tell
-    Symfony to map files from the guest to the host by changing their prefix.
-    This map should be specified at the end of the URL template, using ``&`` and
-    ``>`` as guest-to-host separators:
-
-    .. code-block:: text
-
-        // /path/to/guest/.../file will be opened
-        // as /path/to/host/.../file on the host
-        // and /var/www/app/ as /projects/my_project/ also
-        'myide://%%f:%%l&/path/to/guest/>/path/to/host/&/var/www/app/>/projects/my_project/&...'
-
-        // example for PhpStorm
-        'phpstorm://open?file=%%f&line=%%l&/var/www/app/>/projects/my_project/'
+Now you can use the ``avatars`` package in your templates:
 
-.. _reference-framework-test:
+.. code-block:: html+twig
 
-test
-~~~~
+    <img src="{{ asset('...', 'avatars') }}">
 
-**type**: ``boolean``
+Each package can configure the following options:
 
-If this configuration setting is present (and not ``false``), then the services
-related to testing your application (e.g. ``test.client``) are loaded. This
-setting should be present in your ``test`` environment (usually via
-``config/packages/test/framework.yaml``).
+* :ref:`base_path <reference-assets-base-path>`
+* :ref:`base_urls <reference-assets-base-urls>`
+* :ref:`version_strategy <reference-assets-version-strategy>`
+* :ref:`version <reference-framework-assets-version>`
+* :ref:`version_format <reference-assets-version-format>`
+* :ref:`json_manifest_path <reference-assets-json-manifest-path>`
+* :ref:`strict_mode <reference-assets-strict-mode>`
 
-.. seealso::
+.. _reference-assets-strict-mode:
 
-    For more information, see :doc:`/testing`.
+strict_mode
+...........
 
-.. _config-framework-default_locale:
+**type**: ``boolean`` **default**: ``false``
 
-default_locale
-~~~~~~~~~~~~~~
+When enabled, the strict mode asserts that all requested assets are in the
+manifest file. This option is useful to detect typos or missing assets, the
+recommended value is ``%kernel.debug%``.
 
-**type**: ``string`` **default**: ``en``
+.. _reference-framework-assets-version:
+.. _ref-framework-assets-version:
 
-The default locale is used if no ``_locale`` routing parameter has been
-set. It is available with the
-:method:`Request::getDefaultLocale <Symfony\\Component\\HttpFoundation\\Request::getDefaultLocale>`
-method.
+version
+.......
 
-.. seealso::
+**type**: ``string``
 
-    You can read more information about the default locale in
-    :ref:`translation-default-locale`.
+This option is used to *bust* the cache on assets by globally adding a query
+parameter to all rendered asset paths (e.g. ``/images/logo.png?v2``). This
+applies only to assets rendered via the Twig ``asset()`` function (or PHP
+equivalent).
 
-.. _reference-translator-enabled-locales:
-.. _reference-enabled-locales:
+For example, suppose you have the following:
 
-enabled_locales
-...............
+.. code-block:: html+twig
 
-**type**: ``array`` **default**: ``[]`` (empty array = enable all locales)
+    <img src="{{ asset('images/logo.png') }}" alt="Symfony!"/>
 
-Symfony applications generate by default the translation files for validation
-and security messages in all locales. If your application only uses some
-locales, use this option to restrict the files generated by Symfony and improve
-performance a bit:
+By default, this will render a path to your image such as ``/images/logo.png``.
+Now, activate the ``version`` option:
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/translation.yaml
+        # config/packages/framework.yaml
         framework:
-            enabled_locales: ['en', 'es']
+            # ...
+            assets:
+                version: 'v2'
 
     .. code-block:: xml
 
-        <!-- config/packages/translation.xml -->
+        <!-- config/packages/framework.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -443,81 +399,89 @@ performance a bit:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <enabled-locale>en</enabled-locale>
-                <enabled-locale>es</enabled-locale>
+                <framework:assets version="v2"/>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/translation.php
+        // config/packages/framework.php
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->enabledLocales(['en', 'es']);
-        };
+            // ...
+            $framework->assets()
+                ->version('v2');
+        };
 
-An added bonus of defining the enabled locales is that they are automatically
-added as a requirement of the :ref:`special _locale parameter <routing-locale-parameter>`.
-For example, if you define this value as ``['ar', 'he', 'ja', 'zh']``, the
-``_locale`` routing parameter will have an ``ar|he|ja|zh`` requirement. If some
-user makes requests with a locale not included in this option, they'll see a 404 error.
+Now, the same asset will be rendered as ``/images/logo.png?v2`` If you use
+this feature, you **must** manually increment the ``version`` value
+before each deployment so that the query parameters change.
 
-set_content_language_from_locale
-................................
+You can also control how the query string works via the `version_format`_
+option.
 
-**type**: ``boolean`` **default**: ``false``
+.. note::
 
-If this option is set to ``true``, the response will have a ``Content-Language``
-HTTP header set with the ``Request`` locale.
+    This parameter cannot be set at the same time as ``version_strategy`` or ``json_manifest_path``.
 
-set_locale_from_accept_language
-...............................
+.. tip::
 
-**type**: ``boolean`` **default**: ``false``
+    As with all settings, you can use a parameter as value for the
+    ``version``. This makes it easier to increment the cache on each
+    deployment.
 
-If this option is set to ``true``, the ``Request`` locale will automatically be
-set to the value of the ``Accept-Language`` HTTP header.
+.. _reference-templating-version-format:
+.. _reference-assets-version-format:
 
-When the ``_locale`` request attribute is passed, the ``Accept-Language`` header
-is ignored.
+version_format
+..............
 
-disallow_search_engine_index
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+**type**: ``string`` **default**: ``%%s?%%s``
 
-**type**: ``boolean`` **default**: ``true`` when the debug mode is enabled, ``false`` otherwise.
+This specifies a :phpfunction:`sprintf` pattern that will be used with the
+`version`_ option to construct an asset's path. By default, the pattern
+adds the asset's version as a query string. For example, if
+``version_format`` is set to ``%%s?version=%%s`` and ``version``
+is set to ``5``, the asset's path would be ``/images/logo.png?version=5``.
 
-If ``true``, Symfony adds a ``X-Robots-Tag: noindex`` HTTP tag to all responses
-(unless your own app adds that header, in which case it's not modified). This
-`X-Robots-Tag HTTP header`_ tells search engines to not index your web site.
-This option is a protection measure in case you accidentally publish your site
-in debug mode.
+.. note::
 
-.. _configuration-framework-trusted-hosts:
+    All percentage signs (``%``) in the format string must be doubled to
+    escape the character. Without escaping, values might inadvertently be
+    interpreted as :ref:`service-container-parameters`.
 
-trusted_hosts
-~~~~~~~~~~~~~
+.. tip::
 
-**type**: ``array`` | ``string`` **default**: ``[]``
+    Some CDN's do not support cache-busting via query strings, so injecting
+    the version into the actual file path is necessary. Thankfully,
+    ``version_format`` is not limited to producing versioned query
+    strings.
 
-A lot of different attacks have been discovered relying on inconsistencies
-in handling the ``Host`` header by various software (web servers, reverse
-proxies, web frameworks, etc.). Basically, every time the framework is
-generating an absolute URL (when sending an email to reset a password for
-instance), the host might have been manipulated by an attacker.
+    The pattern receives the asset's original path and version as its first
+    and second parameters, respectively. Since the asset's path is one
+    parameter, you cannot modify it in-place (e.g. ``/images/logo-v5.png``);
+    however, you can prefix the asset's path using a pattern of
+    ``version-%%2$s/%%1$s``, which would result in the path
+    ``version-5/images/logo.png``.
 
-.. seealso::
+    URL rewrite rules could then be used to disregard the version prefix
+    before serving the asset. Alternatively, you could copy assets to the
+    appropriate version path as part of your deployment process and forgot
+    any URL rewriting. The latter option is useful if you would like older
+    asset versions to remain accessible at their original URL.
 
-    You can read `HTTP Host header attacks`_ for more information about
-    these kinds of attacks.
+.. _reference-assets-version-strategy:
+.. _reference-templating-version-strategy:
 
-The Symfony :method:`Request::getHost() <Symfony\\Component\\HttpFoundation\\Request::getHost>`
-method might be vulnerable to some of these attacks because it depends on
-the configuration of your web server. One simple solution to avoid these
-attacks is to configure a list of hosts that your Symfony application can respond
-to. That's the purpose of this ``trusted_hosts`` option. If the incoming
-request's hostname doesn't match one of the regular expressions in this list,
-the application won't respond and the user will receive a 400 response.
+version_strategy
+................
+
+**type**: ``string`` **default**: ``null``
+
+The service id of the :doc:`asset version strategy </frontend/custom_version_strategy>`
+applied to the assets. This option can be set globally for all assets and
+individually for each asset package:
 
 .. configuration-block::
 
@@ -525,7 +489,19 @@ the application won't respond and the user will receive a 400 response.
 
         # config/packages/framework.yaml
         framework:
-            trusted_hosts:  ['^example\.com$', '^example\.org$']
+            assets:
+                # this strategy is applied to every asset (including packages)
+                version_strategy: 'app.asset.my_versioning_strategy'
+                packages:
+                    foo_package:
+                        # this package removes any versioning (its assets won't be versioned)
+                        version: ~
+                    bar_package:
+                        # this package uses its own strategy (the default strategy is ignored)
+                        version_strategy: 'app.asset.another_version_strategy'
+                    baz_package:
+                        # this package inherits the default strategy
+                        base_path: '/images'
 
     .. code-block:: xml
 
@@ -534,14 +510,24 @@ the application won't respond and the user will receive a 400 response.
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
+            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:trusted-host>^example\.com$</framework:trusted-host>
-                <framework:trusted-host>^example\.org$</framework:trusted-host>
-                <!-- ... -->
+                <framework:assets version-strategy="app.asset.my_versioning_strategy">
+                    <!-- this package removes any versioning (its assets won't be versioned) -->
+                    <framework:package
+                        name="foo_package"
+                        version="null"/>
+                    <!-- this package uses its own strategy (the default strategy is ignored) -->
+                    <framework:package
+                        name="bar_package"
+                        version-strategy="app.asset.another_version_strategy"/>
+                    <!-- this package inherits the default strategy -->
+                    <framework:package
+                        name="baz_package"
+                        base_path="/images"/>
+                </framework:assets>
             </framework:config>
         </container>
 
@@ -551,79 +537,117 @@ the application won't respond and the user will receive a 400 response.
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->trustedHosts(['^example\.com$', '^example\.org$']);
+            // ...
+            $framework->assets()
+                ->versionStrategy('app.asset.my_versioning_strategy');
+
+            $framework->assets()->package('foo_package')
+                // this package removes any versioning (its assets won't be versioned)
+                ->version(null);
+
+            $framework->assets()->package('bar_package')
+                // this package uses its own strategy (the default strategy is ignored)
+                ->versionStrategy('app.asset.another_version_strategy');
+
+            $framework->assets()->package('baz_package')
+                // this package inherits the default strategy
+                ->basePath('/images');
         };
 
-Hosts can also be configured to respond to any subdomain, via
-``^(.+\.)?example\.com$`` for instance.
+.. note::
 
-In addition, you can also set the trusted hosts in the front controller
-using the ``Request::setTrustedHosts()`` method::
+    This parameter cannot be set at the same time as ``version`` or ``json_manifest_path``.
 
-    // public/index.php
-    Request::setTrustedHosts(['^(.+\.)?example\.com$', '^(.+\.)?example\.org$']);
+.. _reference-cache:
 
-The default value for this option is an empty array, meaning that the application
-can respond to any given host.
+cache
+~~~~~
 
-.. seealso::
+.. _reference-cache-app:
 
-    Read more about this in the `Security Advisory Blog post`_.
+app
+...
 
-.. _reference-framework-form:
+**type**: ``string`` **default**: ``cache.adapter.filesystem``
 
-form
-~~~~
+The cache adapter used by the ``cache.app`` service. The FrameworkBundle
+ships with multiple adapters: ``cache.adapter.apcu``, ``cache.adapter.system``,
+``cache.adapter.filesystem``, ``cache.adapter.psr6``, ``cache.adapter.redis``,
+``cache.adapter.memcached``, ``cache.adapter.pdo`` and
+``cache.adapter.doctrine_dbal``.
 
-.. _reference-form-enabled:
+There's also a special adapter called ``cache.adapter.array`` which stores
+contents in memory using a PHP array and it's used to disable caching (mostly on
+the ``dev`` environment).
 
-enabled
-.......
+.. tip::
 
-**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
+    It might be tough to understand at the beginning, so to avoid confusion
+    remember that all pools perform the same actions but on different medium
+    given the adapter they are based on. Internally, a pool wraps the definition
+    of an adapter.
 
-Whether to enable the form services or not in the service container. If
-you don't use forms, setting this to ``false`` may increase your application's
-performance because less services will be loaded into the container.
+default_doctrine_provider
+.........................
 
-This option will automatically be set to ``true`` when one of the child
-settings is configured.
+**type**: ``string``
 
-.. note::
+The service name to use as your default Doctrine provider. The provider is
+available as the ``cache.default_doctrine_provider`` service.
 
-    This will automatically enable the `validation`_.
+default_memcached_provider
+..........................
 
-.. seealso::
+**type**: ``string`` **default**: ``memcached://localhost``
 
-    For more details, see :doc:`/forms`.
+The DSN to use by the Memcached provider. The provider is available as the ``cache.default_memcached_provider``
+service.
 
-.. _reference-form-field-name:
+default_pdo_provider
+....................
 
-field_name
-..........
+**type**: ``string`` **default**: ``doctrine.dbal.default_connection``
 
-**type**: ``string`` **default**: ``_token``
+The service id of the database connection, which should be either a PDO or a
+Doctrine DBAL instance. The provider is available as the ``cache.default_pdo_provider``
+service.
 
-This is the field name that you should give to the CSRF token field of your forms.
+default_psr6_provider
+.....................
 
-.. _reference-framework-csrf-protection:
+**type**: ``string``
 
-csrf_protection
-~~~~~~~~~~~~~~~
+The service name to use as your default PSR-6 provider. It is available as
+the ``cache.default_psr6_provider`` service.
 
-.. seealso::
+default_redis_provider
+......................
 
-    For more information about CSRF protection, see :doc:`/security/csrf`.
+**type**: ``string`` **default**: ``redis://localhost``
 
-.. _reference-csrf_protection-enabled:
+The DSN to use by the Redis provider. The provider is available as the ``cache.default_redis_provider``
+service.
 
-enabled
-.......
+directory
+.........
 
-**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
+**type**: ``string`` **default**: ``%kernel.cache_dir%/pools``
 
-This option can be used to disable CSRF protection on *all* forms. But you
-can also :ref:`disable CSRF protection on individual forms <form-csrf-customization>`.
+The path to the cache directory used by services inheriting from the
+``cache.adapter.filesystem`` adapter (including ``cache.app``).
+
+pools
+.....
+
+**type**: ``array``
+
+A list of cache pools to be created by the framework extension.
+
+.. seealso::
+
+    For more information about how pools work, see :ref:`cache pools <component-cache-cache-pools>`.
+
+To configure a Redis cache pool with a default lifetime of 1 hour, do the following:
 
 .. configuration-block::
 
@@ -631,8 +655,11 @@ can also :ref:`disable CSRF protection on individual forms <form-csrf-customizat
 
         # config/packages/framework.yaml
         framework:
-            # ...
-            csrf_protection: true
+            cache:
+                pools:
+                    cache.mycache:
+                        adapter: cache.adapter.redis
+                        default_lifetime: 3600
 
     .. code-block:: xml
 
@@ -643,10 +670,17 @@ can also :ref:`disable CSRF protection on individual forms <form-csrf-customizat
             xmlns:framework="http://symfony.com/schema/dic/symfony"
             xsi:schemaLocation="http://symfony.com/schema/dic/services
                 https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony
-                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
             <framework:config>
-                <framework:csrf-protection enabled="true"/>
+                <framework:cache>
+                    <framework:pool
+                        name="cache.mycache"
+                        adapter="cache.adapter.redis"
+                        default-lifetime="3600"
+                    />
+                </framework:cache>
+                <!-- ... -->
             </framework:config>
         </container>
 
@@ -654,46 +688,138 @@ can also :ref:`disable CSRF protection on individual forms <form-csrf-customizat
 
         // config/packages/framework.php
         use Symfony\Config\FrameworkConfig;
+
         return static function (FrameworkConfig $framework): void {
-            $framework->csrfProtection()
-                ->enabled(true)
-            ;
+            $framework->cache()
+                ->pool('cache.mycache')
+                    ->adapters(['cache.adapter.redis'])
+                    ->defaultLifetime(3600);
         };
 
-If you're using forms, but want to avoid starting your session (e.g. using
-forms in an API-only website), ``csrf_protection`` will need to be set to
-``false``.
+adapter
+"""""""
 
-.. _config-framework-error_controller:
+**type**: ``string`` **default**: ``cache.app``
 
-error_controller
-~~~~~~~~~~~~~~~~
+The service name of the adapter to use. You can specify one of the default
+services that follow the pattern ``cache.adapter.[type]``. Alternatively you
+can specify another cache pool as base, which will make this pool inherit the
+settings from the base pool as defaults.
 
-**type**: ``string`` **default**: ``error_controller``
+.. note::
 
-This is the controller that is called when an exception is thrown anywhere in
-your application. The default controller
-(:class:`Symfony\\Component\\HttpKernel\\Controller\\ErrorController`)
-renders specific templates under different error conditions (see
-:doc:`/controller/error_pages`).
+    Your service needs to implement the ``Psr\Cache\CacheItemPoolInterface`` interface.
 
-esi
-~~~
+clearer
+"""""""
+
+**type**: ``string``
+
+The cache clearer used to clear your PSR-6 cache.
 
 .. seealso::
 
-    You can read more about Edge Side Includes (ESI) in :ref:`edge-side-includes`.
+    For more information, see :class:`Symfony\\Component\\HttpKernel\\CacheClearer\\Psr6CacheClearer`.
 
-.. _reference-esi-enabled:
+default_lifetime
+""""""""""""""""
 
-enabled
-.......
+**type**: ``integer`` | ``string``
+
+Default lifetime of your cache items. Give an integer value to set the default
+lifetime in seconds. A string value could be ISO 8601 time interval, like ``"PT5M"``
+or a PHP date expression that is accepted by ``strtotime()``, like ``"5 minutes"``.
+
+If no value is provided, the cache adapter will fallback to the default value on
+the actual cache storage.
+
+.. _reference-cache-pools-name:
+
+name
+""""
+
+**type**: ``prototype``
+
+Name of the pool you want to create.
+
+.. note::
+
+    Your pool name must differ from ``cache.app`` or ``cache.system``.
+
+provider
+""""""""
+
+**type**: ``string``
+
+Overwrite the default service name or DSN respectively, if you do not want to
+use what is configured as ``default_X_provider`` under ``cache``. See the
+description of the default provider setting above for information on how to
+specify your specific provider.
+
+public
+""""""
 
 **type**: ``boolean`` **default**: ``false``
 
-Whether to enable the edge side includes support in the framework.
+Whether your service should be public or not.
 
-You can also set ``esi`` to ``true`` to enable it:
+tags
+""""
+
+**type**: ``boolean`` | ``string`` **default**: ``null``
+
+Whether your service should be able to handle tags or not.
+Can also be the service id of another cache pool where tags will be stored.
+
+.. _reference-cache-prefix-seed:
+
+prefix_seed
+...........
+
+**type**: ``string`` **default**: ``_%kernel.project_dir%.%kernel.container_class%``
+
+This value is used as part of the "namespace" generated for the
+cache item keys. A common practice is to use the unique name of the application
+(e.g. ``symfony.com``) because that prevents naming collisions when deploying
+multiple applications into the same path (on different servers) that share the
+same cache backend.
+
+It's also useful when using `blue/green deployment`_ strategies and more
+generally, when you need to abstract out the actual deployment directory (for
+example, when warming caches offline).
+
+.. note::
+
+    The ``prefix_seed`` option is used at compile time. This means
+    that any change made to this value after container's compilation
+    will have no effect.
+
+.. _reference-cache-system:
+
+system
+......
+
+**type**: ``string`` **default**: ``cache.adapter.system``
+
+The cache adapter used by the ``cache.system`` service. It supports the same
+adapters available for the ``cache.app`` service.
+
+.. _reference-framework-csrf-protection:
+
+csrf_protection
+~~~~~~~~~~~~~~~
+
+.. seealso::
+
+    For more information about CSRF protection, see :doc:`/security/csrf`.
+
+enabled
+.......
+
+**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
+
+This option can be used to disable CSRF protection on *all* forms. But you
+can also :ref:`disable CSRF protection on individual forms <form-csrf-customization>`.
 
 .. configuration-block::
 
@@ -701,7 +827,8 @@ You can also set ``esi`` to ``true`` to enable it:
 
         # config/packages/framework.yaml
         framework:
-            esi: true
+            # ...
+            csrf_protection: true
 
     .. code-block:: xml
 
@@ -712,10 +839,10 @@ You can also set ``esi`` to ``true`` to enable it:
             xmlns:framework="http://symfony.com/schema/dic/symfony"
             xsi:schemaLocation="http://symfony.com/schema/dic/services
                 https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
-
+                http://symfony.com/schema/dic/symfony
+                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
             <framework:config>
-                <framework:esi/>
+                <framework:csrf-protection enabled="true"/>
             </framework:config>
         </container>
 
@@ -723,83 +850,95 @@ You can also set ``esi`` to ``true`` to enable it:
 
         // config/packages/framework.php
         use Symfony\Config\FrameworkConfig;
-
         return static function (FrameworkConfig $framework): void {
-            $framework->esi()->enabled(true);
+            $framework->csrfProtection()
+                ->enabled(true)
+            ;
         };
 
-fragments
-~~~~~~~~~
+If you're using forms, but want to avoid starting your session (e.g. using
+forms in an API-only website), ``csrf_protection`` will need to be set to
+``false``.
 
-.. seealso::
+stateless_token_ids
+...................
 
-    Learn more about fragments in the
-    :ref:`HTTP Cache article <http_cache-fragments>`.
+**type**: ``array`` **default**: ``[]``
 
-.. _reference-fragments-enabled:
+The list of CSRF token ids that will use :ref:`stateless CSRF protection <csrf-stateless-tokens>`.
 
-enabled
-.......
+.. versionadded:: 7.2
 
-**type**: ``boolean`` **default**: ``false``
+    The ``stateless_token_ids`` option was introduced in Symfony 7.2.
 
-Whether to enable the fragment listener or not. The fragment listener is
-used to render ESI fragments independently of the rest of the page.
+check_header
+............
 
-This setting is automatically set to ``true`` when one of the child settings
-is configured.
+**type**: ``integer`` or ``bool`` **default**: ``false``
 
-hinclude_default_template
-.........................
+Whether to check the CSRF token in an HTTP header in addition to the cookie when
+using :ref:`stateless CSRF protection <csrf-stateless-tokens>`. You can also set
+this to ``2`` (the value of the ``CHECK_ONLY_HEADER`` constant on the
+:class:`Symfony\\Component\\Security\\Csrf\\SameOriginCsrfTokenManager` class)
+to check only the header and ignore the cookie.
 
-**type**: ``string`` **default**: ``null``
+.. versionadded:: 7.2
 
-Sets the content shown during the loading of the fragment or when JavaScript
-is disabled. This can be either a template name or the content itself.
+    The ``check_header`` option was introduced in Symfony 7.2.
 
-.. seealso::
+cookie_name
+...........
 
-    See :ref:`templates-hinclude` for more information about hinclude.
+**type**: ``string`` **default**: ``csrf-token``
 
-.. _reference-fragments-path:
+The name of the cookie (and HTTP header) to use for the double-submit when using
+:ref:`stateless CSRF protection <csrf-stateless-tokens>`.
 
-path
-....
+.. versionadded:: 7.2
 
-**type**: ``string`` **default**: ``/_fragment``
+    The ``cookie_name`` option was introduced in Symfony 7.2.
 
-The path prefix for fragments. The fragment listener will only be executed
-when the request starts with this path.
+.. _config-framework-default_locale:
 
-.. _reference-http-client:
+default_locale
+~~~~~~~~~~~~~~
 
-http_client
-~~~~~~~~~~~
+**type**: ``string`` **default**: ``en``
 
-When the HttpClient component is installed, an HTTP client is available
-as a service named ``http_client`` or using the autowiring alias
-:class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface`.
+The default locale is used if no ``_locale`` routing parameter has been
+set. It is available with the
+:method:`Request::getDefaultLocale <Symfony\\Component\\HttpFoundation\\Request::getDefaultLocale>`
+method.
 
-.. _reference-http-client-default-options:
+.. seealso::
 
-This service can be configured using ``framework.http_client.default_options``:
+    You can read more information about the default locale in
+    :ref:`translation-default-locale`.
+
+.. _reference-translator-enabled-locales:
+.. _reference-enabled-locales:
+
+enabled_locales
+...............
+
+**type**: ``array`` **default**: ``[]`` (empty array = enable all locales)
+
+Symfony applications generate by default the translation files for validation
+and security messages in all locales. If your application only uses some
+locales, use this option to restrict the files generated by Symfony and improve
+performance a bit:
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/framework.yaml
+        # config/packages/translation.yaml
         framework:
-            # ...
-            http_client:
-                max_host_connections: 10
-                default_options:
-                    headers: { 'X-Powered-By': 'ACME App' }
-                    max_redirects: 7
+            enabled_locales: ['en', 'es']
 
     .. code-block:: xml
 
-        <!-- config/packages/framework.xml -->
+        <!-- config/packages/translation.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -809,44 +948,86 @@ This service can be configured using ``framework.http_client.default_options``:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:http-client max-host-connections="10">
-                    <framework:default-options max-redirects="7">
-                        <framework:header name="X-Powered-By">ACME App</framework:header>
-                    </framework:default-options>
-                </framework:http-client>
+                <enabled-locale>en</enabled-locale>
+                <enabled-locale>es</enabled-locale>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/framework.php
-        $container->loadFromExtension('framework', [
-            'http_client' => [
-                'max_host_connections' => 10,
-                'default_options' => [
-                    'headers' => [
-                        'X-Powered-By' => 'ACME App',
-                    ],
-                    'max_redirects' => 7,
-                ],
-            ],
-        ]);
+        // config/packages/translation.php
+        use Symfony\Config\FrameworkConfig;
 
-    .. code-block:: php-standalone
+        return static function (FrameworkConfig $framework): void {
+            $framework->enabledLocales(['en', 'es']);
+        };
 
-        $client = HttpClient::create([
-            'headers' => [
-                'X-Powered-By' => 'ACME App',
-            ],
-            'max_redirects' => 7,
-        ], 10);
+An added bonus of defining the enabled locales is that they are automatically
+added as a requirement of the :ref:`special _locale parameter <routing-locale-parameter>`.
+For example, if you define this value as ``['ar', 'he', 'ja', 'zh']``, the
+``_locale`` routing parameter will have an ``ar|he|ja|zh`` requirement. If some
+user makes requests with a locale not included in this option, they'll see a 404 error.
 
-.. _reference-http-client-scoped-clients:
+set_content_language_from_locale
+................................
 
-Multiple pre-configured HTTP client services can be defined, each with its
-service name defined as a key under ``scoped_clients``. Scoped clients inherit
-the default options defined for the ``http_client`` service. You can override
-these options and can define a few others:
+**type**: ``boolean`` **default**: ``false``
+
+If this option is set to ``true``, the response will have a ``Content-Language``
+HTTP header set with the ``Request`` locale.
+
+set_locale_from_accept_language
+...............................
+
+**type**: ``boolean`` **default**: ``false``
+
+If this option is set to ``true``, the ``Request`` locale will automatically be
+set to the value of the ``Accept-Language`` HTTP header.
+
+When the ``_locale`` request attribute is passed, the ``Accept-Language`` header
+is ignored.
+
+disallow_search_engine_index
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``true`` when the debug mode is enabled, ``false`` otherwise.
+
+If ``true``, Symfony adds a ``X-Robots-Tag: noindex`` HTTP tag to all responses
+(unless your own app adds that header, in which case it's not modified). This
+`X-Robots-Tag HTTP header`_ tells search engines to not index your web site.
+This option is a protection measure in case you accidentally publish your site
+in debug mode.
+
+.. _config-framework-error_controller:
+
+error_controller
+~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``error_controller``
+
+This is the controller that is called when an exception is thrown anywhere in
+your application. The default controller
+(:class:`Symfony\\Component\\HttpKernel\\Controller\\ErrorController`)
+renders specific templates under different error conditions (see
+:doc:`/controller/error_pages`).
+
+esi
+~~~
+
+.. seealso::
+
+    You can read more about Edge Side Includes (ESI) in :ref:`edge-side-includes`.
+
+.. _reference-esi-enabled:
+
+enabled
+.......
+
+**type**: ``boolean`` **default**: ``false``
+
+Whether to enable the edge side includes support in the framework.
+
+You can also set ``esi`` to ``true`` to enable it:
 
 .. configuration-block::
 
@@ -854,12 +1035,7 @@ these options and can define a few others:
 
         # config/packages/framework.yaml
         framework:
-            # ...
-            http_client:
-                scoped_clients:
-                    my_api.client:
-                        auth_bearer: secret_bearer_token
-                        # ...
+            esi: true
 
     .. code-block:: xml
 
@@ -873,1091 +1049,1090 @@ these options and can define a few others:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:http-client>
-                    <framework:scoped-client name="my_api.client" auth-bearer="secret_bearer_token"/>
-                </framework:http-client>
+                <framework:esi/>
             </framework:config>
         </container>
 
     .. code-block:: php
 
         // config/packages/framework.php
-        $container->loadFromExtension('framework', [
-            'http_client' => [
-                'scoped_clients' => [
-                    'my_api.client' => [
-                        'auth_bearer' => 'secret_bearer_token',
-                        // ...
-                    ],
-                ],
-            ],
-        ]);
+        use Symfony\Config\FrameworkConfig;
 
-    .. code-block:: php-standalone
+        return static function (FrameworkConfig $framework): void {
+            $framework->esi()->enabled(true);
+        };
 
-        $client = HttpClient::createForBaseUri('https://...', [
-            'auth_bearer' => 'secret_bearer_token',
-            // ...
-        ]);
+.. _framework_exceptions:
 
-Options defined for scoped clients apply only to URLs that match either their
-`base_uri`_ or the `scope`_ option when it is defined. Non-matching URLs always
-use default options.
+exceptions
+~~~~~~~~~~
 
-Each scoped client also defines a corresponding named autowiring alias.
-If you use for example
-``Symfony\Contracts\HttpClient\HttpClientInterface $myApiClient``
-as the type and name of an argument, autowiring will inject the ``my_api.client``
-service into your autowired classes.
+**type**: ``array``
 
-auth_basic
-..........
+Defines the :ref:`log level </logging>`, :ref:`log channel </logging/channels_handlers>`
+and HTTP status code applied to the exceptions that match the given exception class:
 
-**type**: ``string``
+.. configuration-block::
 
-The username and password used to create the ``Authorization`` HTTP header
-used in HTTP Basic authentication. The value of this option must follow the
-format ``username:password``.
+    .. code-block:: yaml
 
-auth_bearer
-...........
+        # config/packages/exceptions.yaml
+        framework:
+            exceptions:
+                Symfony\Component\HttpKernel\Exception\BadRequestHttpException:
+                    log_level: 'debug'
+                    status_code: 422
+                    log_channel: 'custom_channel'
 
-**type**: ``string``
+    .. code-block:: xml
 
-The token used to create the ``Authorization`` HTTP header used in HTTP Bearer
-authentication (also called token authentication).
+        <!-- config/packages/exceptions.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-auth_ntlm
-.........
+            <framework:config>
+                <framework:exception
+                    class="Symfony\Component\HttpKernel\Exception\BadRequestHttpException"
+                    log-level="debug"
+                    status-code="422"
+                    log-channel="custom_channel"
+                />
+                <!-- ... -->
+            </framework:config>
+        </container>
 
-**type**: ``string``
+    .. code-block:: php
 
-The username and password used to create the ``Authorization`` HTTP header used
-in the `Microsoft NTLM authentication protocol`_. The value of this option must
-follow the format ``username:password``. This authentication mechanism requires
-using the cURL-based transport.
+        // config/packages/exceptions.php
+        use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+        use Symfony\Config\FrameworkConfig;
 
-.. _reference-http-client-base-uri:
+        return static function (FrameworkConfig $framework): void {
+            $framework->exception(BadRequestHttpException::class)
+                ->logLevel('debug')
+                ->statusCode(422)
+                ->logChannel('custom_channel')
+            ;
+        };
 
-base_uri
-........
+.. versionadded:: 7.3
 
-**type**: ``string``
+    The ``log_channel`` option was introduced in Symfony 7.3.
 
-URI that is merged into relative URIs, following the rules explained in the
-`RFC 3986`_ standard. This is useful when all the requests you make share a
-common prefix (e.g. ``https://api.github.com/``) so you can avoid adding it to
-every request.
+The order in which you configure exceptions is important because Symfony will
+use the configuration of the first exception that matches ``instanceof``:
 
-Here are some common examples of how ``base_uri`` merging works in practice:
+.. code-block:: yaml
 
-==========================  ==================  =============================
-``base_uri``                Relative URI        Actual Requested URI
-==========================  ==================  =============================
-http://example.org          /bar                http://example.org/bar
-http://example.org/foo      /bar                http://example.org/bar
-http://example.org/foo      bar                 http://example.org/bar
-http://example.org/foo/     /bar                http://example.org/bar
-http://example.org/foo/     bar                 http://example.org/foo/bar
-http://example.org          http://symfony.com  http://symfony.com
-http://example.org/?bar     bar                 http://example.org/bar
-http://example.org/api/v4   /bar                http://example.org/bar
-http://example.org/api/v4/  /bar                http://example.org/bar
-http://example.org/api/v4   bar                 http://example.org/api/bar
-http://example.org/api/v4/  bar                 http://example.org/api/v4/bar
-==========================  ==================  =============================
+        # config/packages/exceptions.yaml
+        framework:
+            exceptions:
+                Exception:
+                    log_level: 'debug'
+                    status_code: 404
+                # The following configuration will never be used because \RuntimeException extends \Exception
+                RuntimeException:
+                    log_level: 'debug'
+                    status_code: 422
 
-bindto
-......
+You can map a status code and a set of headers to an exception thanks
+to the ``#[WithHttpStatus]`` attribute on the exception class::
 
-**type**: ``string``
+    namespace App\Exception;
 
-A network interface name, IP address, a host name or a UNIX socket to use as the
-outgoing network interface.
+    use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
 
-buffer
-......
+    #[WithHttpStatus(422, [
+       'Retry-After' => 10,
+       'X-Custom-Header' => 'header-value',
+    ])]
+    class CustomException extends \Exception
+    {
+    }
 
-**type**: ``boolean`` | ``Closure``
+It is also possible to map a log level on a custom exception class using
+the ``#[WithLogLevel]`` attribute::
 
-Buffering the response means that you can access its content multiple times
-without performing the request again. Buffering is enabled by default when the
-content type of the response is ``text/*``, ``application/json`` or ``application/xml``.
+    namespace App\Exception;
 
-If this option is a boolean value, the response is buffered when the value is
-``true``. If this option is a closure, the response is buffered when the
-returned value is ``true`` (the closure receives as argument an array with the
-response headers).
+    use Psr\Log\LogLevel;
+    use Symfony\Component\HttpKernel\Attribute\WithLogLevel;
 
-cafile
-......
+    #[WithLogLevel(LogLevel::WARNING)]
+    class CustomException extends \Exception
+    {
+    }
 
-**type**: ``string``
+The attributes can also be added to interfaces directly::
 
-The path of the certificate authority file that contains one or more
-certificates used to verify the other servers' certificates.
+    namespace App\Exception;
 
-capath
-......
+    use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
 
-**type**: ``string``
+    #[WithHttpStatus(422)]
+    interface CustomExceptionInterface
+    {
+    }
 
-The path to a directory that contains one or more certificate authority files.
+    class CustomException extends \Exception implements CustomExceptionInterface
+    {
+    }
 
-ciphers
-.......
+.. versionadded:: 7.1
 
-**type**: ``string``
+    Support to use ``#[WithHttpStatus]`` and ``#[WithLogLevel]`` attributes
+    on interfaces was introduced in Symfony 7.1.
 
-A list of the names of the ciphers allowed for the TLS connections. They
-can be separated by colons, commas or spaces (e.g. ``'RC4-SHA:TLS13-AES-128-GCM-SHA256'``).
+.. _reference-framework-form:
 
-crypto_method
-.............
+form
+~~~~
 
-**type**: ``integer``
+.. _reference-form-enabled:
 
-The minimum version of TLS to accept. The value must be one of the
-``STREAM_CRYPTO_METHOD_TLSv*_CLIENT`` constants defined by PHP.
+enabled
+.......
 
-.. versionadded:: 6.3
+**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
 
-    The ``crypto_method`` option was introduced in Symfony 6.3.
+Whether to enable the form services or not in the service container. If
+you don't use forms, setting this to ``false`` may increase your application's
+performance because less services will be loaded into the container.
 
-.. _reference-http-client-retry-delay:
+This option will automatically be set to ``true`` when one of the child
+settings is configured.
 
-delay
-.....
+.. note::
 
-**type**: ``integer`` **default**: ``1000``
+    This will automatically enable the `validation`_.
 
-The initial delay in milliseconds used to compute the waiting time between retries.
+.. seealso::
 
-.. _reference-http-client-retry-enabled:
+    For more details, see :doc:`/forms`.
 
-enabled
-.......
+csrf_protection
+...............
 
-**type**: ``boolean`` **default**: ``false``
+field_name
+''''''''''
 
-Whether to enable the support for retry failed HTTP request or not.
-This setting is automatically set to true when one of the child settings is configured.
+**type**: ``string`` **default**: ``_token``
 
-extra
-.....
+This is the field name that you should give to the CSRF token field of your forms.
 
-**type**: ``array``
+field_attr
+''''''''''
 
-Arbitrary additional data to pass to the HTTP client for further use.
-This can be particularly useful when :ref:`decorating an existing client <extensibility>`.
+**type**: ``array`` **default**: ``['data-controller' => 'csrf-protection']``
 
-.. versionadded:: 6.3
+HTML attributes to add to the CSRF token field of your forms.
 
-    The ``extra`` option has been introduced in Symfony 6.3.
+token_id
+''''''''
 
-.. _http-headers:
+**type**: ``string`` **default**: ``null``
 
-headers
-.......
+The CSRF token ID used to validate the CSRF tokens of your forms. This setting
+applies only to form types that use :ref:`service autoconfiguration <services-autoconfigure>`,
+which typically means your own form types, not those registered by third-party bundles.
 
-**type**: ``array``
+fragments
+~~~~~~~~~
 
-An associative array of the HTTP headers added before making the request. This
-value must use the format ``['header-name' => 'value0, value1, ...']``.
+.. seealso::
 
-.. _reference-http-client-retry-http-codes:
+    Learn more about fragments in the
+    :ref:`HTTP Cache article <http_cache-fragments>`.
 
-http_codes
-..........
+.. _reference-fragments-enabled:
 
-**type**: ``array`` **default**: :method:`Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES`
+enabled
+.......
 
-The list of HTTP status codes that triggers a retry of the request.
+**type**: ``boolean`` **default**: ``false``
 
-http_version
-............
+Whether to enable the fragment listener or not. The fragment listener is
+used to render ESI fragments independently of the rest of the page.
 
-**type**: ``string`` | ``null`` **default**: ``null``
+This setting is automatically set to ``true`` when one of the child settings
+is configured.
 
-The HTTP version to use, typically ``'1.1'``  or ``'2.0'``. Leave it to ``null``
-to let Symfony select the best version automatically.
+hinclude_default_template
+.........................
 
-.. _reference-http-client-retry-jitter:
+**type**: ``string`` **default**: ``null``
 
-jitter
-......
+Sets the content shown during the loading of the fragment or when JavaScript
+is disabled. This can be either a template name or the content itself.
 
-**type**: ``float`` **default**: ``0.1`` (must be between 0.0 and 1.0)
+.. seealso::
 
-This option adds some randomness to the delay. It's useful to avoid sending
-multiple requests to the server at the exact same time. The randomness is
-calculated as ``delay * jitter``. For example: if delay is ``1000ms`` and jitter
-is ``0.2``, the actual delay will be a number between ``800`` and ``1200`` (1000 +/- 20%).
+    See :ref:`templates-hinclude` for more information about hinclude.
 
-local_cert
-..........
+.. _reference-fragments-path:
 
-**type**: ``string``
+path
+....
 
-The path to a file that contains the `PEM formatted`_ certificate used by the
-HTTP client. This is often combined with the ``local_pk`` and ``passphrase``
-options.
+**type**: ``string`` **default**: ``/_fragment``
 
-local_pk
-........
+The path prefix for fragments. The fragment listener will only be executed
+when the request starts with this path.
 
-**type**: ``string``
+handle_all_throwables
+~~~~~~~~~~~~~~~~~~~~~
 
-The path of a file that contains the `PEM formatted`_ private key of the
-certificate defined in the ``local_cert`` option.
+**type**: ``boolean`` **default**: ``true``
 
-.. _reference-http-client-retry-max-delay:
+When set to ``true``, the Symfony kernel will catch all ``\Throwable`` exceptions
+thrown by the application and will turn them into HTTP responses.
 
-max_delay
-.........
+html_sanitizer
+~~~~~~~~~~~~~~
 
-**type**: ``integer`` **default**: ``0``
+The ``html_sanitizer`` option (and its children) are used to configure
+custom HTML sanitizers. Read more about the options in the
+:ref:`HTML sanitizer documentation <html-sanitizer-configuration>`.
 
-The maximum amount of milliseconds initial to wait between retries.
-Use ``0`` to not limit the duration.
+.. _configuration-framework-http_cache:
 
-max_duration
+http_cache
+~~~~~~~~~~
+
+allow_reload
 ............
 
-**type**: ``float`` **default**: ``0``
+**type**: ``boolean`` **default**: ``false``
 
-The maximum execution time, in seconds, that the request and the response are
-allowed to take. A value lower than or equal to 0 means it is unlimited.
+Specifies whether the client can force a cache reload by including a
+Cache-Control "no-cache" directive in the request. Set it to ``true``
+for compliance with RFC 2616.
 
-.. _reference-http-client-max-host-connections:
+allow_revalidate
+................
 
-max_host_connections
-....................
+**type**: ``boolean`` **default**: ``false``
 
-**type**: ``integer`` **default**: ``6``
+Specifies whether the client can force a cache revalidate by including a
+Cache-Control "max-age=0" directive in the request. Set it to ``true``
+for compliance with RFC 2616.
 
-Defines the maximum amount of simultaneously open connections to a single host
-(considering a "host" the same as a "host name + port number" pair). This limit
-also applies for proxy connections, where the proxy is considered to be the host
-for which this limit is applied.
+debug
+.....
 
-max_redirects
-.............
+**type**: ``boolean`` **default**: ``%kernel.debug%``
 
-**type**: ``integer`` **default**: ``20``
+If true, exceptions are thrown when things go wrong. Otherwise, the cache will
+try to carry on and deliver a meaningful response.
 
-The maximum number of redirects to follow. Use ``0`` to not follow any
-redirection.
+default_ttl
+...........
 
-.. _reference-http-client-retry-max-retries:
+**type**: ``integer`` **default**: ``0``
 
-max_retries
-...........
+The number of seconds that a cache entry should be considered fresh when no
+explicit freshness information is provided in a response. Explicit
+Cache-Control or Expires headers override this value.
 
-**type**: ``integer`` **default**: ``3``
+enabled
+.......
 
-The maximum number of retries for failing requests. When the maximum is reached,
-the client returns the last received response.
+**type**: ``boolean`` **default**: ``false``
 
-.. _reference-http-client-retry-multiplier:
+private_headers
+...............
 
-multiplier
-..........
+**type**: ``array`` **default**: ``['Authorization', 'Cookie']``
 
-**type**: ``float`` **default**: ``2``
+Set of request headers that trigger "private" cache-control behavior on responses
+that don't explicitly state whether the response is public or private via a
+Cache-Control directive.
 
-This value is multiplied to the delay each time a retry occurs, to distribute
-retries in time instead of making all of them sequentially.
+skip_response_headers
+.....................
 
-no_proxy
-........
+**type**: ``array`` **default**: ``Set-Cookie``
 
-**type**: ``string`` | ``null`` **default**: ``null``
+Set of response headers that will never be cached even when the response is cacheable
+and public.
 
-A comma separated list of hosts that do not require a proxy to be reached, even
-if one is configured. Use the ``'*'`` wildcard to match all hosts and an empty
-string to match none (disables the proxy).
+stale_if_error
+..............
 
-passphrase
-..........
+**type**: ``integer`` **default**: ``60``
 
-**type**: ``string``
+Specifies the default number of seconds (the granularity is the second) during
+which the cache can serve a stale response when an error is encountered.
+This setting is overridden by the stale-if-error HTTP
+Cache-Control extension (see RFC 5861).
 
-The passphrase used to encrypt the certificate stored in the file defined in the
-``local_cert`` option.
+stale_while_revalidate
+......................
 
-peer_fingerprint
-................
+**type**: ``integer`` **default**: ``2``
 
-**type**: ``array``
+Specifies the default number of seconds (the granularity is the second as the
+Response TTL precision is a second) during which the cache can immediately return
+a stale response while it revalidates it in the background.
+This setting is overridden by the stale-while-revalidate HTTP Cache-Control
+extension (see RFC 5861).
 
-When negotiating a TLS connection, the server sends a certificate
-indicating its identity. A public key is extracted from this certificate and if
-it does not exactly match any of the public keys provided in this option, the
-connection is aborted before sending or receiving any data.
+trace_header
+............
 
-The value of this option is an associative array of ``algorithm => hash``
-(e.g ``['pin-sha256' => '...']``).
+**type**: ``string`` **default**: ``'X-Symfony-Cache'``
 
-proxy
-.....
+Header name to use for traces.
 
-**type**: ``string`` | ``null``
+trace_level
+...........
 
-The HTTP proxy to use to make the requests. Leave it to ``null`` to detect the
-proxy automatically based on your system configuration.
+**type**: ``string`` **possible values**: ``'none'``, ``'short'`` or ``'full'``
 
-query
-.....
+For 'short', a concise trace of the main request will be added as an HTTP header.
+'full' will add traces for all requests (including ESI subrequests).
+(default: ``'full'`` if in debug; ``'none'`` otherwise)
 
-**type**: ``array``
+.. _reference-http-client:
 
-An associative array of the query string values added to the URL before making
-the request. This value must use the format ``['parameter-name' => parameter-value, ...]``.
+http_client
+~~~~~~~~~~~
 
-resolve
-.......
+When the HttpClient component is installed, an HTTP client is available
+as a service named ``http_client`` or using the autowiring alias
+:class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface`.
 
-**type**: ``array``
+.. _reference-http-client-default-options:
 
-A list of hostnames and their IP addresses to pre-populate the DNS cache used by
-the HTTP client in order to avoid a DNS lookup for those hosts. This option is
-useful to improve security when IPs are checked before the URL is passed to the
-client and to make your tests easier.
+This service can be configured using ``framework.http_client.default_options``:
 
-The value of this option is an associative array of ``domain => IP address``
-(e.g ``['symfony.com' => '46.137.106.254', ...]``).
+.. configuration-block::
 
-.. _reference-http-client-retry-failed:
+    .. code-block:: yaml
 
-retry_failed
-............
+        # config/packages/framework.yaml
+        framework:
+            # ...
+            http_client:
+                max_host_connections: 10
+                default_options:
+                    headers: { 'X-Powered-By': 'ACME App' }
+                    max_redirects: 7
 
-**type**: ``array``
+    .. code-block:: xml
 
-This option configures the behavior of the HTTP client when some request fails,
-including which types of requests to retry and how many times. The behavior is
-defined with the following options:
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-* :ref:`delay <reference-http-client-retry-delay>`
-* :ref:`http_codes <reference-http-client-retry-http-codes>`
-* :ref:`jitter <reference-http-client-retry-jitter>`
-* :ref:`max_delay <reference-http-client-retry-max-delay>`
-* :ref:`max_retries <reference-http-client-retry-max-retries>`
-* :ref:`multiplier <reference-http-client-retry-multiplier>`
+            <framework:config>
+                <framework:http-client max-host-connections="10">
+                    <framework:default-options max-redirects="7">
+                        <framework:header name="X-Powered-By">ACME App</framework:header>
+                    </framework:default-options>
+                </framework:http-client>
+            </framework:config>
+        </container>
 
-.. code-block:: yaml
+    .. code-block:: php
 
-    # config/packages/framework.yaml
-    framework:
-        # ...
-        http_client:
-            # ...
-            default_options:
-                retry_failed:
-                    # retry_strategy: app.custom_strategy
-                    http_codes:
-                        0: ['GET', 'HEAD']   # retry network errors if request method is GET or HEAD
-                        429: true            # retry all responses with 429 status code
-                        500: ['GET', 'HEAD']
-                    max_retries: 2
-                    delay: 1000
-                    multiplier: 3
-                    max_delay: 5000
-                    jitter: 0.3
+        // config/packages/framework.php
+        $container->loadFromExtension('framework', [
+            'http_client' => [
+                'max_host_connections' => 10,
+                'default_options' => [
+                    'headers' => [
+                        'X-Powered-By' => 'ACME App',
+                    ],
+                    'max_redirects' => 7,
+                ],
+            ],
+        ]);
 
-            scoped_clients:
-                my_api.client:
-                    # ...
-                    retry_failed:
-                        max_retries: 4
+    .. code-block:: php-standalone
 
-retry_strategy
-..............
+        $client = HttpClient::create([
+            'headers' => [
+                'X-Powered-By' => 'ACME App',
+            ],
+            'max_redirects' => 7,
+        ], 10);
 
-**type**: ``string``
+.. _reference-http-client-scoped-clients:
 
-The service is used to decide if a request should be retried and to compute the
-time to wait between retries. By default, it uses an instance of
-:class:`Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy` configured
-with ``http_codes``, ``delay``, ``max_delay``, ``multiplier`` and ``jitter``
-options. This class has to implement
-:class:`Symfony\\Component\\HttpClient\\Retry\\RetryStrategyInterface`.
+Multiple pre-configured HTTP client services can be defined, each with its
+service name defined as a key under ``scoped_clients``. Scoped clients inherit
+the default options defined for the ``http_client`` service. You can override
+these options and can define a few others:
 
-scope
-.....
+.. configuration-block::
 
-**type**: ``string``
+    .. code-block:: yaml
 
-For scoped clients only: the regular expression that the URL must match before
-applying all other non-default options. By default, the scope is derived from
-`base_uri`_.
+        # config/packages/framework.yaml
+        framework:
+            # ...
+            http_client:
+                scoped_clients:
+                    my_api.client:
+                        auth_bearer: secret_bearer_token
+                        # ...
 
-timeout
-.......
+    .. code-block:: xml
 
-**type**: ``float`` **default**: depends on your PHP config
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-Time, in seconds, to wait for network activity. If the connection is idle for longer, a
-:class:`Symfony\\Component\\HttpClient\\Exception\\TransportException` is thrown.
-Its default value is the same as the value of PHP's `default_socket_timeout`_
-config option.
+            <framework:config>
+                <framework:http-client>
+                    <framework:scoped-client name="my_api.client" auth-bearer="secret_bearer_token"/>
+                </framework:http-client>
+            </framework:config>
+        </container>
 
-verify_host
-...........
+    .. code-block:: php
 
-**type**: ``boolean`` **default**: ``true``
+        // config/packages/framework.php
+        $container->loadFromExtension('framework', [
+            'http_client' => [
+                'scoped_clients' => [
+                    'my_api.client' => [
+                        'auth_bearer' => 'secret_bearer_token',
+                        // ...
+                    ],
+                ],
+            ],
+        ]);
 
-If ``true``, the certificate sent by other servers is verified to ensure that
-their common name matches the host included in the URL. This is usually
-combined with ``verify_peer`` to also verify the certificate authenticity.
+    .. code-block:: php-standalone
 
-verify_peer
+        $client = HttpClient::createForBaseUri('https://...', [
+            'auth_bearer' => 'secret_bearer_token',
+            // ...
+        ]);
+
+Options defined for scoped clients apply only to URLs that match either their
+`base_uri`_ or the `scope`_ option when it is defined. Non-matching URLs always
+use default options.
+
+Each scoped client also defines a corresponding named autowiring alias.
+If you use for example
+``Symfony\Contracts\HttpClient\HttpClientInterface $myApiClient``
+as the type and name of an argument, autowiring will inject the ``my_api.client``
+service into your autowired classes.
+
+auth_basic
+..........
+
+**type**: ``string``
+
+The username and password used to create the ``Authorization`` HTTP header
+used in HTTP Basic authentication. The value of this option must follow the
+format ``username:password``.
+
+auth_bearer
 ...........
 
-**type**: ``boolean`` **default**: ``true``
+**type**: ``string``
 
-If ``true``, the certificate sent by other servers when negotiating a TLS
-connection is verified for authenticity. Authenticating the certificate is not
-enough to be sure about the server, so you should combine this with the
-``verify_host`` option.
+The token used to create the ``Authorization`` HTTP header used in HTTP Bearer
+authentication (also called token authentication).
 
-html_sanitizer
-~~~~~~~~~~~~~~
+auth_ntlm
+.........
 
-.. versionadded:: 6.1
+**type**: ``string``
 
-    The HTML sanitizer configuration was introduced in Symfony 6.1.
+The username and password used to create the ``Authorization`` HTTP header used
+in the `Microsoft NTLM authentication protocol`_. The value of this option must
+follow the format ``username:password``. This authentication mechanism requires
+using the cURL-based transport.
 
-The ``html_sanitizer`` option (and its children) are used to configure
-custom HTML sanitizers. Read more about the options in the
-:ref:`HTML sanitizer documentation <html-sanitizer-configuration>`.
+.. _reference-http-client-base-uri:
 
-profiler
-~~~~~~~~
+base_uri
+........
 
-.. _reference-profiler-enabled:
+**type**: ``string``
 
-enabled
-.......
+URI that is merged into relative URIs, following the rules explained in the
+`RFC 3986`_ standard. This is useful when all the requests you make share a
+common prefix (e.g. ``https://api.github.com/``) so you can avoid adding it to
+every request.
 
-**type**: ``boolean`` **default**: ``false``
+Here are some common examples of how ``base_uri`` merging works in practice:
 
-The profiler can be enabled by setting this option to ``true``. When you
-install it using Symfony Flex, the profiler is enabled in the ``dev``
-and ``test`` environments.
+==========================  ==================  =============================
+``base_uri``                Relative URI        Actual Requested URI
+==========================  ==================  =============================
+http://example.org          /bar                http://example.org/bar
+http://example.org/foo      /bar                http://example.org/bar
+http://example.org/foo      bar                 http://example.org/bar
+http://example.org/foo/     /bar                http://example.org/bar
+http://example.org/foo/     bar                 http://example.org/foo/bar
+http://example.org          http://symfony.com  http://symfony.com
+http://example.org/?bar     bar                 http://example.org/bar
+http://example.org/api/v4   /bar                http://example.org/bar
+http://example.org/api/v4/  /bar                http://example.org/bar
+http://example.org/api/v4   bar                 http://example.org/api/bar
+http://example.org/api/v4/  bar                 http://example.org/api/v4/bar
+==========================  ==================  =============================
 
-.. note::
+bindto
+......
 
-    The profiler works independently from the Web Developer Toolbar, see
-    the :doc:`WebProfilerBundle configuration </reference/configuration/web_profiler>`
-    on how to disable/enable the toolbar.
+**type**: ``string``
 
-collect
-.......
+A network interface name, IP address, a host name or a UNIX socket to use as the
+outgoing network interface.
 
-**type**: ``boolean`` **default**: ``true``
+buffer
+......
 
-This option configures the way the profiler behaves when it is enabled. If set
-to ``true``, the profiler collects data for all requests. If you want to only
-collect information on-demand, you can set the ``collect`` flag to ``false`` and
-activate the data collectors manually::
+**type**: ``boolean`` | ``Closure``
 
-    $profiler->enable();
+Buffering the response means that you can access its content multiple times
+without performing the request again. Buffering is enabled by default when the
+content type of the response is ``text/*``, ``application/json`` or ``application/xml``.
+
+If this option is a boolean value, the response is buffered when the value is
+``true``. If this option is a closure, the response is buffered when the
+returned value is ``true`` (the closure receives as argument an array with the
+response headers).
+
+cafile
+......
 
-collect_parameter
-.................
+**type**: ``string``
 
-**type**: ``string`` **default**: ``null``
+The path of the certificate authority file that contains one or more
+certificates used to verify the other servers' certificates.
 
-This specifies name of a query parameter, a body parameter or a request attribute
-used to enable or disable collection of data by the profiler for each request.
-Combine it with the ``collect`` option to enable/disable the profiler on demand:
+capath
+......
 
-* If the ``collect`` option is set to ``true`` but this parameter exists in a
-  request and has any value other than ``true``, ``yes``, ``on`` or ``1``, the
-  request data will not be collected;
-* If the ``collect`` option is set to ``false``, but this parameter exists in a
-  request and has value of ``true``, ``yes``, ``on`` or ``1``, the request data
-  will be collected.
+**type**: ``string``
 
-only_exceptions
-...............
+The path to a directory that contains one or more certificate authority files.
 
-**type**: ``boolean`` **default**: ``false``
+ciphers
+.......
 
-When this is set to ``true``, the profiler will only be enabled when an
-exception is thrown during the handling of the request.
+**type**: ``string``
 
-.. _only_master_requests:
+A list of the names of the ciphers allowed for the TLS connections. They
+can be separated by colons, commas or spaces (e.g. ``'RC4-SHA:TLS13-AES-128-GCM-SHA256'``).
 
-only_main_requests
-..................
+crypto_method
+.............
 
-**type**: ``boolean`` **default**: ``false``
+**type**: ``integer``
 
-When this is set to ``true``, the profiler will only be enabled on the main
-requests (and not on the subrequests).
+The minimum version of TLS to accept. The value must be one of the
+``STREAM_CRYPTO_METHOD_TLSv*_CLIENT`` constants defined by PHP.
 
-.. _profiler-dsn:
+.. _reference-http-client-retry-delay:
 
-dsn
-...
+delay
+.....
 
-**type**: ``string`` **default**: ``file:%kernel.cache_dir%/profiler``
+**type**: ``integer`` **default**: ``1000``
 
-The DSN where to store the profiling information.
+The initial delay in milliseconds used to compute the waiting time between retries.
 
-.. _collect_serializer_data:
+.. _reference-http-client-retry-enabled:
 
-collect_serializer_data
-.......................
+enabled
+.......
 
 **type**: ``boolean`` **default**: ``false``
 
-Set this option to ``true`` to enable the serializer data collector and its
-profiler panel. When this option is ``true``, all normalizers and encoders are
-decorated by traceable implementations that collect profiling information about them.
+Whether to enable the support for retry failed HTTP request or not.
+This setting is automatically set to true when one of the child settings is configured.
 
-.. versionadded:: 6.1
+extra
+.....
 
-    The ``collect_serializer_data`` option was introduced in Symfony 6.1.
+**type**: ``array``
 
-rate_limiter
-~~~~~~~~~~~~
+Arbitrary additional data to pass to the HTTP client for further use.
+This can be particularly useful when :ref:`decorating an existing client <extensibility>`.
 
-.. _reference-rate-limiter-name:
+.. _http-headers:
 
-name
-....
+headers
+.......
 
-**type**: ``prototype``
+**type**: ``array``
 
-Name of the rate limiter you want to create.
+An associative array of the HTTP headers added before making the request. This
+value must use the format ``['header-name' => 'value0, value1, ...']``.
 
-lock_factory
-""""""""""""
+.. _reference-http-client-retry-http-codes:
 
-**type**: ``string`` **default:** ``lock.factory``
+http_codes
+..........
 
-The service that is used to create a lock. The service has to be an instance of
-the :class:`Symfony\\Component\\Lock\\LockFactory` class.
+**type**: ``array`` **default**: :method:`Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES`
 
-policy
-""""""
+The list of HTTP status codes that triggers a retry of the request.
 
-**type**: ``string`` **required**
+http_version
+............
 
-The name of the rate limiting algorithm to use. Example names are ``fixed_window``,
-``sliding_window`` and ``no_limit``. See :ref:`Rate Limiter Policies <rate-limiter-policies>`)
-for more information.
+**type**: ``string`` | ``null`` **default**: ``null``
 
-request
-~~~~~~~
+The HTTP version to use, typically ``'1.1'``  or ``'2.0'``. Leave it to ``null``
+to let Symfony select the best version automatically.
 
-formats
-.......
+.. _reference-http-client-retry-jitter:
 
-**type**: ``array`` **default**: ``[]``
+jitter
+......
 
-This setting is used to associate additional request formats (e.g. ``html``)
-to one or more mime types (e.g. ``text/html``), which will allow you to use the
-format & mime types to call
-:method:`Request::getFormat($mimeType) <Symfony\\Component\\HttpFoundation\\Request::getFormat>` or
-:method:`Request::getMimeType($format) <Symfony\\Component\\HttpFoundation\\Request::getMimeType>`.
+**type**: ``float`` **default**: ``0.1`` (must be between 0.0 and 1.0)
 
-In practice, this is important because Symfony uses it to automatically set the
-``Content-Type`` header on the ``Response`` (if you don't explicitly set one).
-If you pass an array of mime types, the first will be used for the header.
+This option adds some randomness to the delay. It's useful to avoid sending
+multiple requests to the server at the exact same time. The randomness is
+calculated as ``delay * jitter``. For example: if delay is ``1000ms`` and jitter
+is ``0.2``, the actual delay will be a number between ``800`` and ``1200`` (1000 +/- 20%).
 
-To configure a ``jsonp`` format:
+local_cert
+..........
 
-.. configuration-block::
+**type**: ``string``
 
-    .. code-block:: yaml
+The path to a file that contains the `PEM formatted`_ certificate used by the
+HTTP client. This is often combined with the ``local_pk`` and ``passphrase``
+options.
 
-        # config/packages/framework.yaml
-        framework:
-            request:
-                formats:
-                    jsonp: 'application/javascript'
+local_pk
+........
 
-    .. code-block:: xml
+**type**: ``string``
 
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
+The path of a file that contains the `PEM formatted`_ private key of the
+certificate defined in the ``local_cert`` option.
 
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony
-                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+.. _reference-http-client-retry-max-delay:
 
-            <framework:config>
-                <framework:request>
-                    <framework:format name="jsonp">
-                        <framework:mime-type>application/javascript</framework:mime-type>
-                    </framework:format>
-                </framework:request>
-            </framework:config>
-        </container>
+max_delay
+.........
 
-    .. code-block:: php
+**type**: ``integer`` **default**: ``0``
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+The maximum amount of milliseconds initial to wait between retries.
+Use ``0`` to not limit the duration.
 
-        return static function (FrameworkConfig $framework): void {
-            $framework->request()
-                ->format('jsonp', 'application/javascript');
-        };
+max_duration
+............
 
-router
-~~~~~~
+**type**: ``float`` **default**: ``0``
 
-resource
-........
+The maximum execution time, in seconds, that the request and the response are
+allowed to take. A value lower than or equal to 0 means it is unlimited.
 
-**type**: ``string`` **required**
+.. _reference-http-client-max-host-connections:
 
-The path the main routing resource (e.g. a YAML file) that contains the
-routes and imports the router should load.
+max_host_connections
+....................
 
-.. _reference-router-type:
+**type**: ``integer`` **default**: ``6``
 
-type
-....
+Defines the maximum amount of simultaneously open connections to a single host
+(considering a "host" the same as a "host name + port number" pair). This limit
+also applies for proxy connections, where the proxy is considered to be the host
+for which this limit is applied.
 
-**type**: ``string``
+max_redirects
+.............
 
-The type of the resource to hint the loaders about the format. This isn't
-needed when you use the default routers with the expected file extensions
-(``.xml``, ``.yaml``, ``.php``).
+**type**: ``integer`` **default**: ``20``
 
-default_uri
-...........
+The maximum number of redirects to follow. Use ``0`` to not follow any
+redirection.
 
-**type**: ``string``
+.. _reference-http-client-retry-max-retries:
 
-The default URI used to generate URLs in a non-HTTP context (see
-:ref:`Generating URLs in Commands <router-generate-urls-commands>`).
+max_retries
+...........
 
-http_port
-.........
+**type**: ``integer`` **default**: ``3``
 
-**type**: ``integer`` **default**: ``80``
+The maximum number of retries for failing requests. When the maximum is reached,
+the client returns the last received response.
 
-The port for normal http requests (this is used when matching the scheme).
+.. _reference-http-client-retry-multiplier:
 
-https_port
+multiplier
 ..........
 
-**type**: ``integer`` **default**: ``443``
-
-The port for https requests (this is used when matching the scheme).
-
-strict_requirements
-...................
+**type**: ``float`` **default**: ``2``
 
-**type**: ``mixed`` **default**: ``true``
+This value is multiplied to the delay each time a retry occurs, to distribute
+retries in time instead of making all of them sequentially.
 
-Determines the routing generator behavior. When generating a route that
-has specific :ref:`parameter requirements <routing-requirements>`, the generator
-can behave differently in case the used parameters do not meet these requirements.
+no_proxy
+........
 
-The value can be one of:
+**type**: ``string`` | ``null`` **default**: ``null``
 
-``true``
-    Throw an exception when the requirements are not met;
-``false``
-    Disable exceptions when the requirements are not met and return ``''``
-    instead;
-``null``
-    Disable checking the requirements (thus, match the route even when the
-    requirements don't match).
+A comma separated list of hosts that do not require a proxy to be reached, even
+if one is configured. Use the ``'*'`` wildcard to match all hosts and an empty
+string to match none (disables the proxy).
 
-``true`` is recommended in the development environment, while ``false``
-or ``null`` might be preferred in production.
+passphrase
+..........
 
-utf8
-....
+**type**: ``string``
 
-**type**: ``boolean`` **default**: ``true``
+The passphrase used to encrypt the certificate stored in the file defined in the
+``local_cert`` option.
 
-When this option is set to ``true``, the regular expressions used in the
-:ref:`requirements of route parameters <routing-requirements>` will be run
-using the `utf-8 modifier`_. This will for example match any UTF-8 character
-when using ``.``, instead of matching only a single byte.
+peer_fingerprint
+................
 
-If the charset of your application is UTF-8 (as defined in the
-:ref:`getCharset() method <configuration-kernel-charset>` of your kernel) it's
-recommended setting it to ``true``. This will make non-UTF8 URLs to generate 404
-errors.
+**type**: ``array``
 
-cache_dir
-.........
+When negotiating a TLS connection, the server sends a certificate
+indicating its identity. A public key is extracted from this certificate and if
+it does not exactly match any of the public keys provided in this option, the
+connection is aborted before sending or receiving any data.
 
-**type**: ``string`` **default**: ``%kernel.cache_dir%``
+The value of this option is an associative array of ``algorithm => hash``
+(e.g ``['pin-sha256' => '...']``).
 
-The directory where routing information will be cached. Can be set to
-``~`` (``null``) to disable route caching.
+proxy
+.....
 
-.. versionadded:: 6.2
+**type**: ``string`` | ``null``
 
-    The ``cache_dir`` setting was introduced in Symfony 6.2.
+The HTTP proxy to use to make the requests. Leave it to ``null`` to detect the
+proxy automatically based on your system configuration.
 
-secrets
-~~~~~~~
+query
+.....
 
-enabled
-.......
+**type**: ``array``
 
-**type**: ``boolean`` **default**: ``true``
+An associative array of the query string values added to the URL before making
+the request. This value must use the format ``['parameter-name' => parameter-value, ...]``.
 
-Whether to enable or not secrets managements.
+rate_limiter
+............
 
-decryption_env_var
-..................
+**type**: ``string``
 
-**type**: ``string`` **default**: ``base64:default::SYMFONY_DECRYPTION_SECRET``
+The service ID of the rate limiter used to limit the number of HTTP requests
+within a certain period. The service must implement the
+:class:`Symfony\\Component\\RateLimiter\\LimiterInterface`.
 
-The env var name that contains the vault decryption secret. By default, this
-value will be decoded from base64.
+.. versionadded:: 7.1
 
-local_dotenv_file
-.................
+    The ``rate_limiter`` option was introduced in Symfony 7.1.
 
-**type**: ``string`` **default**: ``%kernel.project_dir%/.env.%kernel.environment%.local``
+resolve
+.......
 
-The path to the local ``.env`` file. This file must contain the vault
-decryption key, given by the ``decryption_env_var`` option.
+**type**: ``array``
 
-vault_directory
-...............
+A list of hostnames and their IP addresses to pre-populate the DNS cache used by
+the HTTP client in order to avoid a DNS lookup for those hosts. This option is
+useful to improve security when IPs are checked before the URL is passed to the
+client and to make your tests easier.
 
-**type**: ``string`` **default**: ``%kernel.project_dir%/config/secrets/%kernel.runtime_environment%``
+The value of this option is an associative array of ``domain => IP address``
+(e.g ``['symfony.com' => '46.137.106.254', ...]``).
 
-The directory to store the secret vault. By default, the path includes the value
-of the :ref:`kernel.runtime_environment <configuration-kernel-runtime-environment>`
-parameter.
+.. _reference-http-client-retry-failed:
 
-.. _config-framework-session:
+retry_failed
+............
 
-session
-~~~~~~~
+**type**: ``array``
 
-.. _storage_id:
+This option configures the behavior of the HTTP client when some request fails,
+including which types of requests to retry and how many times. The behavior is
+defined with the following options:
 
-storage_factory_id
-..................
+* :ref:`delay <reference-http-client-retry-delay>`
+* :ref:`http_codes <reference-http-client-retry-http-codes>`
+* :ref:`jitter <reference-http-client-retry-jitter>`
+* :ref:`max_delay <reference-http-client-retry-max-delay>`
+* :ref:`max_retries <reference-http-client-retry-max-retries>`
+* :ref:`multiplier <reference-http-client-retry-multiplier>`
 
-**type**: ``string`` **default**: ``session.storage.factory.native``
+.. code-block:: yaml
 
-The service ID used for creating the ``SessionStorageInterface`` that stores
-the session. This service is available in the Symfony application via the
-``session.storage.factory`` service alias. The class has to implement
-:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageFactoryInterface`.
-To see a list of all available storages, run:
+    # config/packages/framework.yaml
+    framework:
+        # ...
+        http_client:
+            # ...
+            default_options:
+                retry_failed:
+                    # retry_strategy: app.custom_strategy
+                    http_codes:
+                        0: ['GET', 'HEAD']   # retry network errors if request method is GET or HEAD
+                        429: true            # retry all responses with 429 status code
+                        500: ['GET', 'HEAD']
+                    max_retries: 2
+                    delay: 1000
+                    multiplier: 3
+                    max_delay: 5000
+                    jitter: 0.3
 
-.. code-block:: terminal
+            scoped_clients:
+                my_api.client:
+                    # ...
+                    retry_failed:
+                        max_retries: 4
 
-    $ php bin/console debug:container session.storage.factory.
+retry_strategy
+..............
 
-.. _config-framework-session-handler-id:
+**type**: ``string``
 
-handler_id
-..........
+The service is used to decide if a request should be retried and to compute the
+time to wait between retries. By default, it uses an instance of
+:class:`Symfony\\Component\\HttpClient\\Retry\\GenericRetryStrategy` configured
+with ``http_codes``, ``delay``, ``max_delay``, ``multiplier`` and ``jitter``
+options. This class has to implement
+:class:`Symfony\\Component\\HttpClient\\Retry\\RetryStrategyInterface`.
 
-**type**: ``string`` **default**: ``session.handler.native_file``
+scope
+.....
 
-The service id or DSN used for session storage. The default value ``'session.handler.native_file'``
-will let Symfony manage the sessions itself using files to store the session metadata.
-Set it to ``null`` to use the native PHP session mechanism.
-It is possible to :ref:`store sessions in a database <session-database>`,
-and also to configure the session handler with a DSN:
+**type**: ``string``
 
-.. configuration-block::
+For scoped clients only: the regular expression that the URL must match before
+applying all other non-default options. By default, the scope is derived from
+`base_uri`_.
 
-    .. code-block:: yaml
+timeout
+.......
 
-        # config/packages/framework.yaml
-        framework:
-            session:
-                # a few possible examples
-                handler_id: 'redis://localhost'
-                handler_id: '%env(REDIS_URL)%'
-                handler_id: '%env(DATABASE_URL)%'
-                handler_id: 'file://%kernel.project_dir%/var/sessions'
+**type**: ``float`` **default**: depends on your PHP config
 
-    .. code-block:: xml
+Time, in seconds, to wait for network activity. If the connection is idle for longer, a
+:class:`Symfony\\Component\\HttpClient\\Exception\\TransportException` is thrown.
+Its default value is the same as the value of PHP's `default_socket_timeout`_
+config option.
 
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
-            <framework:config>
-                <!-- a few possible examples -->
-                <framework:session enabled="true"
-                    handler-id="redis://localhost"
-                    handler-id="%env(REDIS_URL)%"
-                    handler-id="%env(DATABASE_URL)%"
-                    handler-id="file://%kernel.project_dir%/var/sessions"/>
-            </framework:config>
-        </container>
+verify_host
+...........
 
-    .. code-block:: php
+**type**: ``boolean`` **default**: ``true``
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
-        use function Symfony\Component\DependencyInjection\Loader\Configurator\env;
+If ``true``, the certificate sent by other servers is verified to ensure that
+their common name matches the host included in the URL. This is usually
+combined with ``verify_peer`` to also verify the certificate authenticity.
 
-        return static function (FrameworkConfig $framework): void {
-            // ...
+verify_peer
+...........
 
-            $framework->session()
-                // a few possible examples
-                ->handlerId('redis://localhost')
-                ->handlerId(env('REDIS_URL'))
-                ->handlerId(env('DATABASE_URL'))
-                ->handlerId('file://%kernel.project_dir%/var/sessions');
-        };
+**type**: ``boolean`` **default**: ``true``
 
-.. note::
+If ``true``, the certificate sent by other servers when negotiating a TLS
+connection is verified for authenticity. Authenticating the certificate is not
+enough to be sure about the server, so you should combine this with the
+``verify_host`` option.
 
-    Supported DSN protocols are the following:
+ .. _configuration-framework-http_method_override:
 
-    * ``file``
-    * ``redis``
-    * ``rediss`` (Redis over TLS)
-    * ``memcached`` (requires :doc:`symfony/cache </components/cache>`)
-    * ``pdo_oci`` (requires :doc:`doctrine/dbal </doctrine/dbal>`)
-    * ``mssql``
-    * ``mysql``
-    * ``mysql2``
-    * ``pgsql``
-    * ``postgres``
-    * ``postgresql``
-    * ``sqlsrv``
-    * ``sqlite``
-    * ``sqlite3``
+http_method_override
+~~~~~~~~~~~~~~~~~~~~
 
-.. _name:
+**type**: ``boolean`` **default**: ``false``
 
-name
-....
+This determines whether the ``_method`` request parameter is used as the
+intended HTTP method on POST requests. If enabled, the
+:method:`Request::enableHttpMethodParameterOverride <Symfony\\Component\\HttpFoundation\\Request::enableHttpMethodParameterOverride>`
+method gets called automatically. It becomes the service container parameter
+named ``kernel.http_method_override``.
 
-**type**: ``string``
+.. seealso::
 
-This specifies the name of the session cookie.
+    :ref:`Changing the Action and HTTP Method <forms-change-action-method>` of
+    Symfony forms.
 
-If not set, ``php.ini``'s `session.name`_ directive will be relied on.
+.. warning::
 
-cookie_lifetime
-...............
+    If you're using the :ref:`HttpCache Reverse Proxy <symfony2-reverse-proxy>`
+    with this option, the kernel will ignore the ``_method`` parameter,
+    which could lead to errors.
 
-**type**: ``integer``
+    To fix this, invoke the ``enableHttpMethodParameterOverride()`` method
+    before creating the ``Request`` object::
 
-This determines the lifetime of the session - in seconds.
-Setting this value to ``0`` means the cookie is valid for
-the length of the browser session.
+        // public/index.php
 
-If not set, ``php.ini``'s `session.cookie_lifetime`_ directive will be relied on.
+        // ...
+        $kernel = new CacheKernel($kernel);
 
-cookie_path
-...........
+        Request::enableHttpMethodParameterOverride(); // <-- add this line
+        $request = Request::createFromGlobals();
+        // ...
 
-**type**: ``string``
+.. _reference-framework-ide:
 
-This determines the path to set in the session cookie.
+ide
+~~~
 
-If not set, ``php.ini``'s `session.cookie_path`_ directive will be relied on.
+**type**: ``string`` **default**: ``%env(default::SYMFONY_IDE)%``
 
-cache_limiter
-.............
+Symfony turns file paths seen in variable dumps and exception messages into
+links that open those files right inside your browser. If you prefer to open
+those files in your favorite IDE or text editor, set this option to any of the
+following values: ``phpstorm``, ``sublime``, ``textmate``, ``macvim``, ``emacs``,
+``atom`` and ``vscode``.
 
-**type**: ``string`` **default**: ``0``
+.. note::
 
-If set to ``0``, Symfony won't set any particular header related to the cache
-and it will rely on ``php.ini``'s `session.cache_limiter`_ directive.
+    The ``phpstorm`` option is supported natively by PhpStorm on macOS and
+    Windows; Linux requires installing `phpstorm-url-handler`_.
 
-Unlike the other session options, ``cache_limiter`` is set as a regular
-:ref:`container parameter <configuration-parameters>`:
+If you use another editor, the expected configuration value is a URL template
+that contains an ``%f`` placeholder where the file path is expected and ``%l``
+placeholder for the line number (percentage signs (``%``) must be escaped by
+doubling them to prevent Symfony from interpreting them as container parameters).
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/services.yaml
-        parameters:
-            session.storage.options:
-                cache_limiter: 0
+        # config/packages/framework.yaml
+        framework:
+            ide: 'myide://open?url=file://%%f&line=%%l'
 
     .. code-block:: xml
 
-        <!-- config/services.xml -->
+        <!-- config/packages/framework.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
             xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd">
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-            <parameters>
-                <parameter key="session.storage.options" type="collection">
-                    <parameter key="cache_limiter">0</parameter>
-                </parameter>
-            </parameters>
+            <framework:config ide="myide://open?url=file://%%f&line=%%l"/>
         </container>
 
     .. code-block:: php
 
-        // config/services.php
-        $container->setParameter('session.storage.options', [
-            'cache_limiter' => 0,
-        ]);
-
-Be aware that if you configure it, you'll have to set other session-related options
-as parameters as well.
-
-cookie_domain
-.............
-
-**type**: ``string``
-
-This determines the domain to set in the session cookie.
-
-If not set, ``php.ini``'s `session.cookie_domain`_ directive will be relied on.
-
-cookie_samesite
-...............
-
-**type**: ``string`` or ``null`` **default**: ``null``
-
-It controls the way cookies are sent when the HTTP request did not originate
-from the same domain that is associated with the cookies. Setting this option is
-recommended to mitigate `CSRF security attacks`_.
-
-By default, browsers send all cookies related to the domain of the HTTP request.
-This may be a problem for example when you visit a forum and some malicious
-comment includes a link like ``https://some-bank.com/?send_money_to=attacker&amount=1000``.
-If you were previously logged into your bank website, the browser will send all
-those cookies when making that HTTP request.
-
-The possible values for this option are:
-
-* ``null``, use ``php.ini``'s `session.cookie_samesite`_ directive.
-* ``'none'`` (or the ``Symfony\Component\HttpFoundation\Cookie::SAMESITE_NONE`` constant), use it to allow
-  sending of cookies when the HTTP request originated from a different domain
-  (previously this was the default behavior of null, but in newer browsers ``'lax'``
-  would be applied when the header has not been set)
-* ``'strict'`` (or the ``Cookie::SAMESITE_STRICT`` constant), use it to never
-  send any cookie when the HTTP request did not originate from the same domain.
-* ``'lax'`` (or the ``Cookie::SAMESITE_LAX`` constant), use it to allow sending
-  cookies when the request originated from a different domain, but only when the
-  user consciously made the request (by clicking a link or submitting a form
-  with the ``GET`` method).
-
-cookie_secure
-.............
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
 
-**type**: ``boolean`` or ``'auto'``
+        return static function (FrameworkConfig $framework): void {
+            $framework->ide('myide://open?url=file://%%f&line=%%l');
+        };
 
-This determines whether cookies should only be sent over secure connections. In
-addition to ``true`` and ``false``, there's a special ``'auto'`` value that
-means ``true`` for HTTPS requests and ``false`` for HTTP requests.
+Since every developer uses a different IDE, the recommended way to enable this
+feature is to configure it on a system level. First, you can define this option
+in the ``SYMFONY_IDE`` environment variable, which Symfony reads automatically
+when ``framework.ide`` config is not set.
 
-If not set, ``php.ini``'s `session.cookie_secure`_ directive will be relied on.
+Another alternative is to set the ``xdebug.file_link_format`` option in your
+``php.ini`` configuration file. The format to use is the same as for the
+``framework.ide`` option, but without the need to escape the percent signs
+(``%``) by doubling them:
 
-cookie_httponly
-...............
+.. code-block:: ini
 
-**type**: ``boolean`` **default**: ``true``
+    // example for PhpStorm
+    xdebug.file_link_format="phpstorm://open?file=%f&line=%l"
 
-This determines whether cookies should only be accessible through the HTTP
-protocol. This means that the cookie won't be accessible by scripting
-languages, such as JavaScript. This setting can effectively help to reduce
-identity theft through :ref:`XSS attacks <xss-attacks>`.
+    // example for PhpStorm with Jetbrains Toolbox
+    xdebug.file_link_format="jetbrains://phpstorm/navigate/reference?project=example&path=%f:%l"
 
-gc_divisor
-..........
+    // example for Sublime Text
+    xdebug.file_link_format="subl://open?url=file://%f&line=%l"
 
-**type**: ``integer``
+.. note::
 
-See `gc_probability`_.
+    If both ``framework.ide`` and ``xdebug.file_link_format`` are defined,
+    Symfony uses the value of the ``xdebug.file_link_format`` option.
 
-If not set, ``php.ini``'s `session.gc_divisor`_ directive will be relied on.
+.. tip::
 
-gc_probability
-..............
+    Setting the ``xdebug.file_link_format`` ini option works even if the Xdebug
+    extension is not enabled.
 
-**type**: ``integer`` **default**: ``1``
+.. tip::
 
-This defines the probability that the garbage collector (GC) process is
-started on every session initialization. The probability is calculated by
-using ``gc_probability`` / ``gc_divisor``, e.g. 1/100 means there is a 1%
-chance that the GC process will start on each request.
+    When running your app in a container or in a virtual machine, you can tell
+    Symfony to map files from the guest to the host by changing their prefix.
+    This map should be specified at the end of the URL template, using ``&`` and
+    ``>`` as guest-to-host separators:
 
-gc_maxlifetime
-..............
+    .. code-block:: text
 
-**type**: ``integer``
+        // /path/to/guest/.../file will be opened
+        // as /path/to/host/.../file on the host
+        // and /var/www/app/ as /projects/my_project/ also
+        'myide://%%f:%%l&/path/to/guest/>/path/to/host/&/var/www/app/>/projects/my_project/&...'
 
-This determines the number of seconds after which data will be seen as "garbage"
-and potentially cleaned up. Garbage collection may occur during session
-start and depends on `gc_divisor`_ and `gc_probability`_.
+        // example for PhpStorm
+        'phpstorm://open?file=%%f&line=%%l&/var/www/app/>/projects/my_project/'
 
-If not set, ``php.ini``'s `session.gc_maxlifetime`_ directive will be relied on.
+.. _reference-lock:
 
-sid_length
-..........
+lock
+~~~~
 
-**type**: ``integer``
+**type**: ``string`` | ``array``
 
-This determines the length of session ID string, which can be an integer between
-``22`` and ``256`` (both inclusive), ``32`` being the recommended value. Longer
-session IDs are harder to guess.
+The default lock adapter. If not defined, the value is set to ``semaphore`` when
+available, or to ``flock`` otherwise. Store's DSN are also allowed.
 
-If not set, ``php.ini``'s `session.sid_length`_ directive will be relied on.
+.. _reference-lock-enabled:
 
-sid_bits_per_character
-......................
+enabled
+.......
 
-**type**: ``integer``
+**type**: ``boolean`` **default**: ``true``
 
-This determines the number of bits in the encoded session ID character. The possible
-values are ``4`` (0-9, a-f), ``5`` (0-9, a-v), and ``6`` (0-9, a-z, A-Z, "-", ",").
-The more bits results in stronger session ID. ``5`` is recommended value for
-most environments.
+Whether to enable the support for lock or not. This setting is
+automatically set to ``true`` when one of the child settings is configured.
 
-If not set, ``php.ini``'s `session.sid_bits_per_character`_ directive will be relied on.
+.. _reference-lock-resources:
 
-save_path
+resources
 .........
 
-**type**: ``string`` or ``null`` **default**: ``%kernel.cache_dir%/sessions``
-
-This determines the argument to be passed to the save handler. If you choose
-the default file handler, this is the path where the session files are created.
+**type**: ``array``
 
-If ``null``, ``php.ini``'s `session.save_path`_ directive will be relied on:
+A map of lock stores to be created by the framework extension, with
+the name as key and DSN or service id as value:
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/framework.yaml
+        # config/packages/lock.yaml
         framework:
-            session:
-                save_path: ~
+            lock: '%env(LOCK_DSN)%'
 
     .. code-block:: xml
 
-        <!-- config/packages/framework.xml -->
+        <!-- config/packages/lock.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -1967,52 +2142,73 @@ If ``null``, ``php.ini``'s `session.save_path`_ directive will be relied on:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:session save-path="null"/>
+                <framework:lock>
+                    <framework:resource name="default">%env(LOCK_DSN)%</framework:resource>
+                </framework:lock>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/framework.php
+        // config/packages/lock.php
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->session()
-                ->savePath(null);
+            $framework->lock()
+                ->resource('default', [env('LOCK_DSN')]);
         };
 
-.. _reference-session-metadata-update-threshold:
+.. seealso::
 
-metadata_update_threshold
-.........................
+    For more details, see :doc:`/lock`.
 
-**type**: ``integer`` **default**: ``0``
+.. _reference-lock-resources-name:
 
-This is how many seconds to wait between updating/writing the session metadata.
-This can be useful if, for some reason, you want to limit the frequency at which
-the session persists, instead of doing that on every request.
+name
+""""
 
-.. _reference-session-enabled:
+**type**: ``prototype``
 
-enabled
-.......
+Name of the lock you want to create.
 
-**type**: ``boolean`` **default**: ``true``
+mailer
+~~~~~~
 
-Whether to enable the session support in the framework.
+.. _mailer-dsn:
+
+dsn
+...
+
+**type**: ``string`` **default**: ``null``
+
+The DSN used by the mailer. When several DSN may be used, use
+``transports`` option (see below) instead.
+
+envelope
+........
+
+recipients
+""""""""""
+
+**type**: ``array``
+
+The "envelope recipient" which is used as the value of ``RCPT TO`` during the
+the `SMTP session`_. This value overrides any other recipient set in the code.
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/framework.yaml
+        # config/packages/mailer.yaml
         framework:
-            session:
-                enabled: true
+            mailer:
+                dsn: 'smtp://localhost:25'
+                envelope:
+                    recipients: ['admin@symfony.com', 'lead@symfony.com']
 
     .. code-block:: xml
 
-        <!-- config/packages/framework.xml -->
+        <!-- config/packages/mailer.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -2020,110 +2216,105 @@ Whether to enable the session support in the framework.
             xsi:schemaLocation="http://symfony.com/schema/dic/services
                 https://symfony.com/schema/dic/services/services-1.0.xsd
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
-
             <framework:config>
-                <framework:session enabled="true"/>
+                <framework:mailer dsn="smtp://localhost:25">
+                    <framework:envelope>
+                        <framework:recipient>admin@symfony.com</framework:recipient>
+                        <framework:recipient>lead@symfony.com</framework:recipient>
+                    </framework:envelope>
+                </framework:mailer>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+        // config/packages/mailer.php
+        namespace Symfony\Component\DependencyInjection\Loader\Configurator;
 
-        return static function (FrameworkConfig $framework): void {
-            $framework->session()
-                ->enabled(true);
+        return static function (ContainerConfigurator $container): void {
+            $container->extension('framework', [
+                'mailer' => [
+                    'dsn' => 'smtp://localhost:25',
+                    'envelope' => [
+                        'recipients' => [
+                            'admin@symfony.com',
+                            'lead@symfony.com',
+                        ],
+                    ],
+                ],
+            ]);
         };
 
-use_cookies
-...........
-
-**type**: ``boolean``
+sender
+""""""
 
-This specifies if the session ID is stored on the client side using cookies or
-not.
+**type**: ``string``
 
-If not set, ``php.ini``'s `session.use_cookies`_ directive will be relied on.
+The "envelope sender" which is used as the value of ``MAIL FROM`` during the
+`SMTP session`_. This value overrides any other sender set in the code.
 
-ssi
-~~~
+.. _mailer-headers:
 
-enabled
+headers
 .......
 
-**type**: ``boolean`` **default**: ``false``
-
-Whether to enable or not SSI support in your application.
-
-.. _reference-assets:
+**type**: ``array``
 
-assets
-~~~~~~
+Headers to add to emails. The key (``name`` attribute in xml format) is the
+header name and value the header value.
 
-The following options configure the behavior of the
-:ref:`Twig asset() function <reference-twig-function-asset>`.
+.. seealso::
 
-.. _reference-assets-base-path:
+    For more information, see :ref:`Configuring Emails Globally <mailer-configure-email-globally>`
 
-base_path
-.........
+message_bus
+...........
 
-**type**: ``string``
+**type**: ``string`` **default**: ``null`` or default bus if Messenger component is installed
 
-This option allows you to prepend a base path to the URLs generated for assets:
+Service identifier of the message bus to use when using the
+:doc:`Messenger component </messenger>` (e.g. ``messenger.default_bus``).
 
-.. configuration-block::
+transports
+..........
 
-    .. code-block:: yaml
+**type**: ``array``
 
-        # config/packages/framework.yaml
-        framework:
-            # ...
-            assets:
-                base_path: '/images'
+A :ref:`list of DSN <multiple-email-transports>` that can be used by the
+mailer. A transport name is the key and the dsn is the value.
 
-    .. code-block:: xml
+messenger
+~~~~~~~~~
 
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+enabled
+.......
 
-            <framework:config>
-                <framework:assets base-path="/images"/>
-            </framework:config>
-        </container>
+**type**: ``boolean`` **default**: ``true``
 
-    .. code-block:: php
+Whether to enable or not Messenger.
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+.. seealso::
 
-        return static function (FrameworkConfig $framework): void {
-            // ...
-            $framework->assets()
-                ->basePath('/images');
-        };
+    For more details, see the :doc:`Messenger component </messenger>`
+    documentation.
 
-With this configuration, a call to ``asset('logo.png')`` will generate
-``/images/logo.png`` instead of ``/logo.png``.
+php_errors
+~~~~~~~~~~
 
-.. _reference-templating-base-urls:
-.. _reference-assets-base-urls:
+log
+...
 
-base_urls
-.........
+**type**: ``boolean``, ``int`` or ``array<int, string>`` **default**: ``true``
 
-**type**: ``array``
+Use the application logger instead of the PHP logger for logging PHP errors.
+When an integer value is used, it defines a bitmask of PHP errors that will
+be logged. Those integer values must be the same used in the
+`error_reporting PHP option`_. The default log levels will be used for each
+PHP error.
+When a boolean value is used, ``true`` enables logging for all PHP errors
+while ``false`` disables logging entirely.
 
-This option allows you to define base URLs to be used for assets.
-If multiple base URLs are provided, Symfony will select one from the
-collection each time it generates an asset's path:
+This option also accepts a map of PHP errors to log levels:
 
 .. configuration-block::
 
@@ -2131,10 +2322,23 @@ collection each time it generates an asset's path:
 
         # config/packages/framework.yaml
         framework:
-            # ...
-            assets:
-                base_urls:
-                    - 'http://cdn.example.com/'
+            php_errors:
+                log:
+                    !php/const \E_DEPRECATED: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_USER_DEPRECATED: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_NOTICE: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_USER_NOTICE: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_STRICT: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_WARNING: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_USER_WARNING: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_COMPILE_WARNING: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_CORE_WARNING: !php/const Psr\Log\LogLevel::ERROR
+                    !php/const \E_USER_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
+                    !php/const \E_RECOVERABLE_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
+                    !php/const \E_COMPILE_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
+                    !php/const \E_PARSE: !php/const Psr\Log\LogLevel::CRITICAL
+                    !php/const \E_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
+                    !php/const \E_CORE_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
 
     .. code-block:: xml
 
@@ -2148,314 +2352,241 @@ collection each time it generates an asset's path:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:assets base-url="http://cdn.example.com/"/>
+                <!-- in XML configuration you cannot use PHP constants as the value of
+                     the 'type' attribute, which makes this format way less readable.
+                     Consider using YAML or PHP for this configuration -->
+                <framework:log type="8" logLevel="error"/>
+                <framework:log type="2" logLevel="error"/>
+                <!-- ... -->
             </framework:config>
         </container>
 
     .. code-block:: php
 
         // config/packages/framework.php
+        use Psr\Log\LogLevel;
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
+            $framework->phpErrors()->log(\E_DEPRECATED, LogLevel::ERROR);
+            $framework->phpErrors()->log(\E_USER_DEPRECATED, LogLevel::ERROR);
             // ...
-            $framework->assets()
-                ->baseUrls(['http://cdn.example.com/']);
         };
 
-.. _reference-framework-assets-packages:
-
-packages
-........
+throw
+.....
 
-You can group assets into packages, to specify different base URLs for them:
+**type**: ``boolean`` **default**: ``%kernel.debug%``
 
-.. configuration-block::
+Throw PHP errors as ``\ErrorException`` instances. The parameter
+``debug.error_handler.throw_at`` controls the threshold.
 
-    .. code-block:: yaml
+profiler
+~~~~~~~~
 
-        # config/packages/framework.yaml
-        framework:
-            # ...
-            assets:
-                packages:
-                    avatars:
-                        base_urls: 'http://static_cdn.example.com/avatars'
+collect
+.......
 
-    .. code-block:: xml
+**type**: ``boolean`` **default**: ``true``
 
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+This option configures the way the profiler behaves when it is enabled. If set
+to ``true``, the profiler collects data for all requests. If you want to only
+collect information on-demand, you can set the ``collect`` flag to ``false`` and
+activate the data collectors manually::
 
-            <framework:config>
-                <framework:assets>
-                    <framework:package
-                        name="avatars"
-                        base-url="http://static_cdn.example.com/avatars"/>
-                </framework:assets>
-            </framework:config>
-        </container>
+    $profiler->enable();
 
-    .. code-block:: php
+collect_parameter
+.................
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+**type**: ``string`` **default**: ``null``
 
-        return static function (FrameworkConfig $framework): void {
-            // ...
-            $framework->assets()
-                ->package('avatars')
-                    ->baseUrls(['http://static_cdn.example.com/avatars']);
-        };
+This specifies name of a query parameter, a body parameter or a request attribute
+used to enable or disable collection of data by the profiler for each request.
+Combine it with the ``collect`` option to enable/disable the profiler on demand:
 
-Now you can use the ``avatars`` package in your templates:
+* If the ``collect`` option is set to ``true`` but this parameter exists in a
+  request and has any value other than ``true``, ``yes``, ``on`` or ``1``, the
+  request data will not be collected;
+* If the ``collect`` option is set to ``false``, but this parameter exists in a
+  request and has value of ``true``, ``yes``, ``on`` or ``1``, the request data
+  will be collected.
 
-.. code-block:: html+twig
+.. _collect_serializer_data:
 
-    <img src="{{ asset('...', 'avatars') }}">
+collect_serializer_data
+.......................
 
-Each package can configure the following options:
+**type**: ``boolean`` **default**: ``false``
 
-* :ref:`base_path <reference-assets-base-path>`
-* :ref:`base_urls <reference-assets-base-urls>`
-* :ref:`version_strategy <reference-assets-version-strategy>`
-* :ref:`version <reference-framework-assets-version>`
-* :ref:`version_format <reference-assets-version-format>`
-* :ref:`json_manifest_path <reference-assets-json-manifest-path>`
-* :ref:`strict_mode <reference-assets-strict-mode>`
+When this option is ``true``, all normalizers and encoders are
+decorated by traceable implementations that collect profiling information about them.
 
-.. _reference-framework-assets-version:
-.. _ref-framework-assets-version:
+.. deprecated:: 7.3
 
-version
-.......
+    Setting the ``collect_serializer_data`` option to ``false`` is deprecated
+    since Symfony 7.3.
 
-**type**: ``string``
+.. _profiler-dsn:
 
-This option is used to *bust* the cache on assets by globally adding a query
-parameter to all rendered asset paths (e.g. ``/images/logo.png?v2``). This
-applies only to assets rendered via the Twig ``asset()`` function (or PHP
-equivalent).
+dsn
+...
 
-For example, suppose you have the following:
+**type**: ``string`` **default**: ``file:%kernel.cache_dir%/profiler``
 
-.. code-block:: html+twig
+The DSN where to store the profiling information.
 
-    <img src="{{ asset('images/logo.png') }}" alt="Symfony!"/>
+.. _reference-profiler-enabled:
 
-By default, this will render a path to your image such as ``/images/logo.png``.
-Now, activate the ``version`` option:
+enabled
+.......
 
-.. configuration-block::
+**type**: ``boolean`` **default**: ``false``
 
-    .. code-block:: yaml
+The profiler can be enabled by setting this option to ``true``. When you
+install it using Symfony Flex, the profiler is enabled in the ``dev``
+and ``test`` environments.
 
-        # config/packages/framework.yaml
-        framework:
-            # ...
-            assets:
-                version: 'v2'
+.. note::
 
-    .. code-block:: xml
+    The profiler works independently from the Web Developer Toolbar, see
+    the :doc:`WebProfilerBundle configuration </reference/configuration/web_profiler>`
+    on how to disable/enable the toolbar.
 
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+only_exceptions
+...............
 
-            <framework:config>
-                <framework:assets version="v2"/>
-            </framework:config>
-        </container>
+**type**: ``boolean`` **default**: ``false``
 
-    .. code-block:: php
+When this is set to ``true``, the profiler will only be enabled when an
+exception is thrown during the handling of the request.
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+.. _only_master_requests:
 
-        return static function (FrameworkConfig $framework): void {
-            // ...
-            $framework->assets()
-                ->version('v2');
-        };
+only_main_requests
+..................
 
-Now, the same asset will be rendered as ``/images/logo.png?v2`` If you use
-this feature, you **must** manually increment the ``version`` value
-before each deployment so that the query parameters change.
+**type**: ``boolean`` **default**: ``false``
 
-You can also control how the query string works via the `version_format`_
-option.
+When this is set to ``true``, the profiler will only be enabled on the main
+requests (and not on the subrequests).
 
-.. note::
+property_access
+~~~~~~~~~~~~~~~
 
-    This parameter cannot be set at the same time as ``version_strategy`` or ``json_manifest_path``.
+magic_call
+..........
 
-.. tip::
+**type**: ``boolean`` **default**: ``false``
 
-    As with all settings, you can use a parameter as value for the
-    ``version``. This makes it easier to increment the cache on each
-    deployment.
+When enabled, the ``property_accessor`` service uses PHP's
+:ref:`magic __call() method <components-property-access-magic-call>` when
+its ``getValue()`` method is called.
 
-.. _reference-templating-version-format:
-.. _reference-assets-version-format:
+magic_get
+.........
 
-version_format
-..............
+**type**: ``boolean`` **default**: ``true``
 
-**type**: ``string`` **default**: ``%%s?%%s``
+When enabled, the ``property_accessor`` service uses PHP's
+:ref:`magic __get() method <components-property-access-magic-get>` when
+its ``getValue()`` method is called.
 
-This specifies a :phpfunction:`sprintf` pattern that will be used with the
-`version`_ option to construct an asset's path. By default, the pattern
-adds the asset's version as a query string. For example, if
-``version_format`` is set to ``%%s?version=%%s`` and ``version``
-is set to ``5``, the asset's path would be ``/images/logo.png?version=5``.
+magic_set
+.........
 
-.. note::
+**type**: ``boolean`` **default**: ``true``
 
-    All percentage signs (``%``) in the format string must be doubled to
-    escape the character. Without escaping, values might inadvertently be
-    interpreted as :ref:`service-container-parameters`.
+When enabled, the ``property_accessor`` service uses PHP's
+:ref:`magic __set() method <components-property-access-writing-to-objects>` when
+its ``setValue()`` method is called.
 
-.. tip::
+throw_exception_on_invalid_index
+................................
 
-    Some CDN's do not support cache-busting via query strings, so injecting
-    the version into the actual file path is necessary. Thankfully,
-    ``version_format`` is not limited to producing versioned query
-    strings.
+**type**: ``boolean`` **default**: ``false``
 
-    The pattern receives the asset's original path and version as its first
-    and second parameters, respectively. Since the asset's path is one
-    parameter, you cannot modify it in-place (e.g. ``/images/logo-v5.png``);
-    however, you can prefix the asset's path using a pattern of
-    ``version-%%2$s/%%1$s``, which would result in the path
-    ``version-5/images/logo.png``.
+When enabled, the ``property_accessor`` service throws an exception when you
+try to access an invalid index of an array.
 
-    URL rewrite rules could then be used to disregard the version prefix
-    before serving the asset. Alternatively, you could copy assets to the
-    appropriate version path as part of your deployment process and forgot
-    any URL rewriting. The latter option is useful if you would like older
-    asset versions to remain accessible at their original URL.
+throw_exception_on_invalid_property_path
+........................................
 
-.. _reference-assets-version-strategy:
-.. _reference-templating-version-strategy:
+**type**: ``boolean`` **default**: ``true``
 
-version_strategy
-................
+When enabled, the ``property_accessor`` service throws an exception when you
+try to access an invalid property path of an object.
 
-**type**: ``string`` **default**: ``null``
+property_info
+~~~~~~~~~~~~~
 
-The service id of the :doc:`asset version strategy </frontend/custom_version_strategy>`
-applied to the assets. This option can be set globally for all assets and
-individually for each asset package:
+.. _reference-property-info-enabled:
 
-.. configuration-block::
+enabled
+.......
 
-    .. code-block:: yaml
+**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
 
-        # config/packages/framework.yaml
-        framework:
-            assets:
-                # this strategy is applied to every asset (including packages)
-                version_strategy: 'app.asset.my_versioning_strategy'
-                packages:
-                    foo_package:
-                        # this package removes any versioning (its assets won't be versioned)
-                        version: ~
-                    bar_package:
-                        # this package uses its own strategy (the default strategy is ignored)
-                        version_strategy: 'app.asset.another_version_strategy'
-                    baz_package:
-                        # this package inherits the default strategy
-                        base_path: '/images'
+with_constructor_extractor
+..........................
 
-    .. code-block:: xml
+**type**: ``boolean`` **default**: ``false``
 
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+Configures the ``property_info`` service to extract property information from the constructor arguments
+using the :ref:`ConstructorExtractor <components-property-information-constructor-extractor>`.
 
-            <framework:config>
-                <framework:assets version-strategy="app.asset.my_versioning_strategy">
-                    <!-- this package removes any versioning (its assets won't be versioned) -->
-                    <framework:package
-                        name="foo_package"
-                        version="null"/>
-                    <!-- this package uses its own strategy (the default strategy is ignored) -->
-                    <framework:package
-                        name="bar_package"
-                        version-strategy="app.asset.another_version_strategy"/>
-                    <!-- this package inherits the default strategy -->
-                    <framework:package
-                        name="baz_package"
-                        base_path="/images"/>
-                </framework:assets>
-            </framework:config>
-        </container>
+.. versionadded:: 7.3
 
-    .. code-block:: php
+    The ``with_constructor_extractor`` option was introduced in Symfony 7.3.
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+rate_limiter
+~~~~~~~~~~~~
 
-        return static function (FrameworkConfig $framework): void {
-            // ...
-            $framework->assets()
-                ->versionStrategy('app.asset.my_versioning_strategy');
+.. _reference-rate-limiter-name:
 
-            $framework->assets()->package('foo_package')
-                // this package removes any versioning (its assets won't be versioned)
-                ->version(null);
+name
+....
 
-            $framework->assets()->package('bar_package')
-                // this package uses its own strategy (the default strategy is ignored)
-                ->versionStrategy('app.asset.another_version_strategy');
+**type**: ``prototype``
 
-            $framework->assets()->package('baz_package')
-                // this package inherits the default strategy
-                ->basePath('/images');
-        };
+Name of the rate limiter you want to create.
 
-.. note::
+lock_factory
+""""""""""""
 
-    This parameter cannot be set at the same time as ``version`` or ``json_manifest_path``.
+**type**: ``string`` **default:** ``lock.factory``
 
-.. _reference-assets-json-manifest-path:
-.. _reference-templating-json-manifest-path:
+The service that is used to create a lock. The service has to be an instance of
+the :class:`Symfony\\Component\\Lock\\LockFactory` class.
 
-json_manifest_path
-..................
+policy
+""""""
 
-**type**: ``string`` **default**: ``null``
+**type**: ``string`` **required**
 
-The file path or absolute URL to a ``manifest.json`` file containing an
-associative array of asset names and their respective compiled names. A common
-cache-busting technique using a "manifest" file works by writing out assets with
-a "hash" appended to their file names (e.g. ``main.ae433f1cb.css``) during a
-front-end compilation routine.
+The name of the rate limiting algorithm to use. Example names are ``fixed_window``,
+``sliding_window`` and ``no_limit``. See :ref:`Rate Limiter Policies <rate-limiter-policies>`)
+for more information.
 
-.. tip::
+request
+~~~~~~~
+
+formats
+.......
+
+**type**: ``array`` **default**: ``[]``
+
+This setting is used to associate additional request formats (e.g. ``html``)
+to one or more mime types (e.g. ``text/html``), which will allow you to use the
+format & mime types to call
+:method:`Request::getFormat($mimeType) <Symfony\\Component\\HttpFoundation\\Request::getFormat>` or
+:method:`Request::getMimeType($format) <Symfony\\Component\\HttpFoundation\\Request::getMimeType>`.
 
-    Symfony's :ref:`Webpack Encore <frontend-webpack-encore>` supports
-    :ref:`outputting hashed assets <encore-long-term-caching>`. Moreover, this
-    can be incorporated into many other workflows, including Webpack and
-    Gulp using `webpack-manifest-plugin`_ and `gulp-rev`_, respectively.
+In practice, this is important because Symfony uses it to automatically set the
+``Content-Type`` header on the ``Response`` (if you don't explicitly set one).
+If you pass an array of mime types, the first will be used for the header.
 
-This option can be set globally for all assets and individually for each asset
-package:
+To configure a ``jsonp`` format:
 
 .. configuration-block::
 
@@ -2463,46 +2594,29 @@ package:
 
         # config/packages/framework.yaml
         framework:
-            assets:
-                # this manifest is applied to every asset (including packages)
-                json_manifest_path: "%kernel.project_dir%/public/build/manifest.json"
-                # you can use absolute URLs too and Symfony will download them automatically
-                # json_manifest_path: 'https://cdn.example.com/manifest.json'
-                packages:
-                    foo_package:
-                        # this package uses its own manifest (the default file is ignored)
-                        json_manifest_path: "%kernel.project_dir%/public/build/a_different_manifest.json"
-                        # Throws an exception when an asset is not found in the manifest
-                        strict_mode: %kernel.debug%
-                    bar_package:
-                        # this package uses the global manifest (the default file is used)
-                        base_path: '/images'
+            request:
+                formats:
+                    jsonp: 'application/javascript'
 
     .. code-block:: xml
 
         <!-- config/packages/framework.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
+
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony
+                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <!-- this manifest is applied to every asset (including packages) -->
-                <framework:assets json-manifest-path="%kernel.project_dir%/public/build/manifest.json">
-                <!-- you can use absolute URLs too and Symfony will download them automatically -->
-                <!-- <framework:assets json-manifest-path="https://cdn.example.com/manifest.json"> -->
-                    <!-- this package uses its own manifest (the default file is ignored) -->
-                    <!-- Throws an exception when an asset is not found in the manifest -->
-                    <framework:package
-                        name="foo_package"
-                        json-manifest-path="%kernel.project_dir%/public/build/a_different_manifest.json" strict-mode="%kernel.debug%"/>
-                    <!-- this package uses the global manifest (the default file is used) -->
-                    <framework:package
-                        name="bar_package"
-                        base-path="/images"/>
-                </framework:assets>
+                <framework:request>
+                    <framework:format name="jsonp">
+                        <framework:mime-type>application/javascript</framework:mime-type>
+                    </framework:format>
+                </framework:request>
             </framework:config>
         </container>
 
@@ -2512,226 +2626,206 @@ package:
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            // ...
-            $framework->assets()
-                // this manifest is applied to every asset (including packages)
-                ->jsonManifestPath('%kernel.project_dir%/public/build/manifest.json');
-
-            // you can use absolute URLs too and Symfony will download them automatically
-            // 'json_manifest_path' => 'https://cdn.example.com/manifest.json',
-            $framework->assets()->package('foo_package')
-                // this package uses its own manifest (the default file is ignored)
-                ->jsonManifestPath('%kernel.project_dir%/public/build/a_different_manifest.json')
-                // Throws an exception when an asset is not found in the manifest
-                ->setStrictMode('%kernel.debug%');
-
-            $framework->assets()->package('bar_package')
-                // this package uses the global manifest (the default file is used)
-                ->basePath('/images');
+            $framework->request()
+                ->format('jsonp', 'application/javascript');
         };
 
-.. note::
-
-    This parameter cannot be set at the same time as ``version`` or ``version_strategy``.
-    Additionally, this option cannot be nullified at the package scope if a global manifest
-    file is specified.
+router
+~~~~~~
 
-.. tip::
+cache_dir
+.........
 
-    If you request an asset that is *not found* in the ``manifest.json`` file, the original -
-    *unmodified* - asset path will be returned.
-    You can set ``strict_mode`` to ``true`` to get an exception when an asset is *not found*.
+**type**: ``string`` **default**: ``%kernel.cache_dir%``
 
-.. note::
+The directory where routing information will be cached. Can be set to
+``~`` (``null``) to disable route caching.
 
-    If a URL is set, the JSON manifest is downloaded on each request using the `http_client`_.
+.. deprecated:: 7.1
 
-.. _reference-assets-strict-mode:
+    Setting the ``cache_dir`` option is deprecated since Symfony 7.1. The routes
+    are now always cached in the ``%kernel.build_dir%`` directory.
 
-strict_mode
+default_uri
 ...........
 
-**type**: ``boolean`` **default**: ``false``
-
-When enabled, the strict mode asserts that all requested assets are in the
-manifest file. This option is useful to detect typos or missing assets, the
-recommended value is ``%kernel.debug%``.
+**type**: ``string``
 
-translator
-~~~~~~~~~~
+The default URI used to generate URLs in a non-HTTP context (see
+:ref:`Generating URLs in Commands <router-generate-urls-commands>`).
 
-cache_dir
+http_port
 .........
 
-**type**: ``string`` | ``null`` **default**: ``%kernel.cache_dir%/translations``
-
-Defines the directory where the translation cache is stored. Use ``null`` to
-disable this cache.
-
-.. _reference-translator-enabled:
-
-enabled
-.......
-
-**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
-
-Whether or not to enable the ``translator`` service in the service container.
-
-.. _fallback:
+**type**: ``integer`` **default**: ``80``
 
-fallbacks
-.........
+The port for normal http requests (this is used when matching the scheme).
 
-**type**: ``string|array`` **default**: value of `default_locale`_
+https_port
+..........
 
-This option is used when the translation key for the current locale wasn't
-found.
+**type**: ``integer`` **default**: ``443``
 
-.. seealso::
+The port for https requests (this is used when matching the scheme).
 
-    For more details, see :doc:`/translation`.
+resource
+........
 
-.. _reference-framework-translator-logging:
+**type**: ``string`` **required**
 
-logging
-.......
+The path the main routing resource (e.g. a YAML file) that contains the
+routes and imports the router should load.
 
-**default**: ``true`` when the debug mode is enabled, ``false`` otherwise.
+strict_requirements
+...................
 
-When ``true``, a log entry is made whenever the translator cannot find a translation
-for a given key. The logs are made to the ``translation`` channel at the
-``debug`` level for keys where there is a translation in the fallback
-locale, and the ``warning`` level if there is no translation to use at all.
+**type**: ``mixed`` **default**: ``true``
 
-.. _reference-framework-translator-formatter:
+Determines the routing generator behavior. When generating a route that
+has specific :ref:`parameter requirements <routing-requirements>`, the generator
+can behave differently in case the used parameters do not meet these requirements.
 
-formatter
-.........
+The value can be one of:
 
-**type**: ``string`` **default**: ``translator.formatter.default``
+``true``
+    Throw an exception when the requirements are not met;
+``false``
+    Disable exceptions when the requirements are not met and return ``''``
+    instead;
+``null``
+    Disable checking the requirements (thus, match the route even when the
+    requirements don't match).
 
-The ID of the service used to format translation messages. The service class
-must implement the :class:`Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface`.
+``true`` is recommended in the development environment, while ``false``
+or ``null`` might be preferred in production.
 
-.. _reference-translator-paths:
+.. _reference-router-type:
 
-paths
-.....
+type
+....
 
-**type**: ``array`` **default**: ``[]``
+**type**: ``string``
 
-This option allows to define an array of paths where the component will look
-for translation files. The later a path is added, the more priority it has
-(translations from later paths overwrite earlier ones). Translations from the
-:ref:`default_path <reference-translator-default_path>` have more priority than
-translations from all these paths.
+The type of the resource to hint the loaders about the format. This isn't
+needed when you use the default routers with the expected file extensions
+(``.xml``, ``.yaml``, ``.php``).
 
-.. _reference-translator-default_path:
+utf8
+....
 
-default_path
-............
+**type**: ``boolean`` **default**: ``true``
 
-**type**: ``string`` **default**: ``%kernel.project_dir%/translations``
+When this option is set to ``true``, the regular expressions used in the
+:ref:`requirements of route parameters <routing-requirements>` will be run
+using the `utf-8 modifier`_. This will for example match any UTF-8 character
+when using ``.``, instead of matching only a single byte.
 
-This option allows to define the path where the application translations files
-are stored.
+If the charset of your application is UTF-8 (as defined in the
+:ref:`getCharset() method <configuration-kernel-charset>` of your kernel) it's
+recommended setting it to ``true``. This will make non-UTF8 URLs to generate 404
+errors.
 
-.. _reference-translator-providers:
+.. _configuration-framework-secret:
 
-providers
-.........
+secret
+~~~~~~
 
-**type**: ``array`` **default**: ``[]``
+**type**: ``string`` **required**
 
-This option enables and configures :ref:`translation providers <translation-providers>`
-to push and pull your translations to/from third party translation services.
+This is a string that should be unique to your application and it's commonly
+used to add more entropy to security related operations. Its value should
+be a series of characters, numbers and symbols chosen randomly and the
+recommended length is around 32 characters.
 
-property_access
-~~~~~~~~~~~~~~~
+In practice, Symfony uses this value for encrypting the cookies used
+in the :doc:`remember me functionality </security/remember_me>` and for
+creating signed URIs when using :ref:`ESI (Edge Side Includes) <edge-side-includes>`.
+That's why you should treat this value as if it were a sensitive credential and
+**never make it public**.
 
-magic_call
-..........
+This option becomes the service container parameter named ``kernel.secret``,
+which you can use whenever the application needs an immutable random string
+to add more entropy.
 
-**type**: ``boolean`` **default**: ``false``
+As with any other security-related parameter, it is a good practice to change
+this value from time to time. However, keep in mind that changing this value
+will invalidate all signed URIs and Remember Me cookies. That's why, after
+changing this value, you should regenerate the application cache and log
+out all the application users.
 
-When enabled, the ``property_accessor`` service uses PHP's
-:ref:`magic __call() method <components-property-access-magic-call>` when
-its ``getValue()`` method is called.
+secrets
+~~~~~~~
 
-magic_get
-.........
+decryption_env_var
+..................
 
-**type**: ``boolean`` **default**: ``true``
+**type**: ``string`` **default**: ``base64:default::SYMFONY_DECRYPTION_SECRET``
 
-When enabled, the ``property_accessor`` service uses PHP's
-:ref:`magic __get() method <components-property-access-magic-get>` when
-its ``getValue()`` method is called.
+The env var name that contains the vault decryption secret. By default, this
+value will be decoded from base64.
 
-magic_set
-.........
+enabled
+.......
 
 **type**: ``boolean`` **default**: ``true``
 
-When enabled, the ``property_accessor`` service uses PHP's
-:ref:`magic __set() method <components-property-access-writing-to-objects>` when
-its ``setValue()`` method is called.
+Whether to enable or not secrets managements.
 
-throw_exception_on_invalid_index
-................................
+local_dotenv_file
+.................
 
-**type**: ``boolean`` **default**: ``false``
+**type**: ``string`` **default**: ``%kernel.project_dir%/.env.%kernel.environment%.local``
 
-When enabled, the ``property_accessor`` service throws an exception when you
-try to access an invalid index of an array.
+The path to the local ``.env`` file. This file must contain the vault
+decryption key, given by the ``decryption_env_var`` option.
 
-throw_exception_on_invalid_property_path
-........................................
+vault_directory
+...............
 
-**type**: ``boolean`` **default**: ``true``
+**type**: ``string`` **default**: ``%kernel.project_dir%/config/secrets/%kernel.runtime_environment%``
 
-When enabled, the ``property_accessor`` service throws an exception when you
-try to access an invalid property path of an object.
+The directory to store the secret vault. By default, the path includes the value
+of the :ref:`kernel.runtime_environment <configuration-kernel-runtime-environment>`
+parameter.
 
-property_info
-~~~~~~~~~~~~~
+semaphore
+~~~~~~~~~
 
-.. _reference-property-info-enabled:
+**type**: ``string`` | ``array``
+
+The default semaphore adapter. Store's DSN are also allowed.
+
+.. _reference-semaphore-enabled:
 
 enabled
 .......
 
-**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
-
-.. _reference-validation:
+**type**: ``boolean`` **default**: ``true``
 
-validation
-~~~~~~~~~~
+Whether to enable the support for semaphore or not. This setting is
+automatically set to ``true`` when one of the child settings is configured.
 
-.. _reference-validation-auto-mapping:
+.. _reference-semaphore-resources:
 
-auto_mapping
-............
+resources
+.........
 
-**type**: ``array`` **default**: ``[]``
+**type**: ``array``
 
-Defines the Doctrine entities that will be introspected to add
-:ref:`automatic validation constraints <automatic_object_validation>` to them:
+A map of semaphore stores to be created by the framework extension, with
+the name as key and DSN or service id as value:
 
 .. configuration-block::
 
     .. code-block:: yaml
 
+        # config/packages/semaphore.yaml
         framework:
-            validation:
-                auto_mapping:
-                    # an empty array means that all entities that belong to that
-                    # namespace will add automatic validation
-                    'App\Entity\': []
-                    'Foo\': ['Foo\Some\Entity', 'Foo\Another\Entity']
+            semaphore: '%env(SEMAPHORE_DSN)%'
 
     .. code-block:: xml
 
-        <!-- config/packages/framework.xml -->
+        <!-- config/packages/semaphore.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -2741,143 +2835,256 @@ Defines the Doctrine entities that will be introspected to add
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:validation>
-                    <framework:auto-mapping>
-                        <framework:service namespace="App\Entity\"/>
-
-                        <framework:service namespace="Foo\">Foo\Some\Entity</framework:service>
-                        <framework:service namespace="Foo\">Foo\Another\Entity</framework:service>
-                    </framework:auto-mapping>
-                </framework:validation>
+                <framework:semaphore>
+                    <framework:resource name="default">%env(SEMAPHORE_DSN)%</framework:resource>
+                </framework:semaphore>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/framework.php
+        // config/packages/semaphore.php
         use Symfony\Config\FrameworkConfig;
+        use function Symfony\Component\DependencyInjection\Loader\Configurator\env;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->validation()
-                ->autoMapping()
-                    ->paths([
-                        'App\\Entity\\' => [],
-                        'Foo\\' => ['Foo\\Some\\Entity', 'Foo\\Another\\Entity'],
-                    ]);
+            $framework->semaphore()
+                ->resource('default', [env('SEMAPHORE_DSN')]);
         };
 
-.. _reference-validation-enabled:
+.. _reference-semaphore-resources-name:
 
-enabled
-.......
+name
+""""
 
-**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
+**type**: ``prototype``
 
-Whether or not to enable validation support.
+Name of the semaphore you want to create.
 
-This option will automatically be set to ``true`` when one of the child
-settings is configured.
+.. _configuration-framework-serializer:
 
-.. _reference-validation-enable_annotations:
+serializer
+~~~~~~~~~~
 
-enable_annotations
-..................
+.. _reference-serializer-circular_reference_handler:
 
-**type**: ``boolean`` **default**: ``true``
+circular_reference_handler
+..........................
+
+**type** ``string``
+
+The service id that is used as the circular reference handler of the default
+serializer. The service has to implement the magic ``__invoke($object)``
+method.
 
-If this option is enabled, validation constraints can be defined using annotations or `PHP attributes`_.
+.. seealso::
+
+    For more information, see
+    :ref:`component-serializer-handling-circular-references`.
+
+default_context
+...............
+
+**type**: ``array`` **default**: ``[]``
+
+A map with default context options that will be used with each ``serialize`` and ``deserialize``
+call. This can be used for example to set the json encoding behavior by setting ``json_encode_options``
+to a `json_encode flags bitmask`_.
 
-.. deprecated:: 6.4
+You can inspect the :ref:`serializer context builders <serializer-using-context-builders>`
+to discover the available settings.
 
-    This option is deprecated since Symfony 6.4, use the ``enable_attributes``
-    option instead.
+.. _reference-serializer-enable_annotations:
 
 enable_attributes
 .................
 
 **type**: ``boolean`` **default**: ``true``
 
-If this option is enabled, validation constraints can be defined using `PHP attributes`_.
+Enables support for `PHP attributes`_ in the serializer component.
 
-translation_domain
-..................
+.. seealso::
 
-**type**: ``string | false`` **default**: ``validators``
+    See :ref:`the reference <reference-attributes-serializer>` for a list of supported annotations.
 
-The translation domain that is used when translating validation constraint
-error messages. Use false to disable translations.
+.. _reference-serializer-enabled:
 
-.. _reference-validation-not-compromised-password:
+enabled
+.......
 
-not_compromised_password
-........................
+**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
 
-The :doc:`NotCompromisedPassword </reference/constraints/NotCompromisedPassword>`
-constraint makes HTTP requests to a public API to check if the given password
-has been compromised in a data breach.
+Whether to enable the ``serializer`` service or not in the service container.
 
-.. _reference-validation-not-compromised-password-enabled:
+.. _reference-serializer-mapping:
 
-enabled
-"""""""
+mapping
+.......
+
+.. _reference-serializer-mapping-paths:
+
+paths
+"""""
+
+**type**: ``array`` **default**: ``[]``
+
+This option allows to define an array of paths with files or directories where
+the component will look for additional serialization files.
+
+.. _reference-serializer-name_converter:
+
+name_converter
+..............
+
+**type**: ``string``
+
+The name converter to use.
+The :class:`Symfony\\Component\\Serializer\\NameConverter\\CamelCaseToSnakeCaseNameConverter`
+name converter can enabled by using the ``serializer.name_converter.camel_case_to_snake_case``
+value.
+
+.. seealso::
+
+    For more information, see :ref:`serializer-name-conversion`.
+
+.. _config-framework-session:
+
+session
+~~~~~~~
+
+cache_limiter
+.............
+
+**type**: ``string`` **default**: ``0``
+
+If set to ``0``, Symfony won't set any particular header related to the cache
+and it will rely on ``php.ini``'s `session.cache_limiter`_ directive.
+
+Unlike the other session options, ``cache_limiter`` is set as a regular
+:ref:`container parameter <configuration-parameters>`:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/services.yaml
+        parameters:
+            session.storage.options:
+                cache_limiter: 0
+
+    .. code-block:: xml
+
+        <!-- config/services.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd">
+
+            <parameters>
+                <parameter key="session.storage.options" type="collection">
+                    <parameter key="cache_limiter">0</parameter>
+                </parameter>
+            </parameters>
+        </container>
+
+    .. code-block:: php
+
+        // config/services.php
+        $container->setParameter('session.storage.options', [
+            'cache_limiter' => 0,
+        ]);
+
+Be aware that if you configure it, you'll have to set other session-related options
+as parameters as well.
+
+cookie_domain
+.............
+
+**type**: ``string``
+
+This determines the domain to set in the session cookie.
+
+If not set, ``php.ini``'s `session.cookie_domain`_ directive will be relied on.
+
+cookie_httponly
+...............
 
 **type**: ``boolean`` **default**: ``true``
 
-If you set this option to ``false``, no HTTP requests will be made and the given
-password will be considered valid. This is useful when you don't want or can't
-make HTTP requests, such as in ``dev`` and ``test`` environments or in
-continuous integration servers.
+This determines whether cookies should only be accessible through the HTTP
+protocol. This means that the cookie won't be accessible by scripting
+languages, such as JavaScript. This setting can effectively help to reduce
+identity theft through :ref:`XSS attacks <xss-attacks>`.
+
+cookie_lifetime
+...............
+
+**type**: ``integer``
+
+This determines the lifetime of the session - in seconds.
+Setting this value to ``0`` means the cookie is valid for
+the length of the browser session.
+
+If not set, ``php.ini``'s `session.cookie_lifetime`_ directive will be relied on.
 
-endpoint
-""""""""
+cookie_path
+...........
 
-**type**: ``string`` **default**: ``null``
+**type**: ``string``
 
-By default, the :doc:`NotCompromisedPassword </reference/constraints/NotCompromisedPassword>`
-constraint uses the public API provided by `haveibeenpwned.com`_. This option
-allows to define a different, but compatible, API endpoint to make the password
-checks. It's useful for example when the Symfony application is run in an
-intranet without public access to the internet.
+This determines the path to set in the session cookie.
 
-static_method
-.............
+If not set, ``php.ini``'s `session.cookie_path`_ directive will be relied on.
 
-**type**: ``string | array`` **default**: ``['loadValidatorMetadata']``
+cookie_samesite
+...............
 
-Defines the name of the static method which is called to load the validation
-metadata of the class. You can define an array of strings with the names of
-several methods. In that case, all of them will be called in that order to load
-the metadata.
+**type**: ``string`` or ``null`` **default**: ``null``
 
-.. _reference-validation-email_validation_mode:
+It controls the way cookies are sent when the HTTP request did not originate
+from the same domain that is associated with the cookies. Setting this option is
+recommended to mitigate `CSRF security attacks`_.
 
-email_validation_mode
-.....................
+By default, browsers send all cookies related to the domain of the HTTP request.
+This may be a problem for example when you visit a forum and some malicious
+comment includes a link like ``https://some-bank.com/?send_money_to=attacker&amount=1000``.
+If you were previously logged into your bank website, the browser will send all
+those cookies when making that HTTP request.
 
-**type**: ``string`` **default**: ``loose``
+The possible values for this option are:
 
-.. deprecated:: 6.2
+* ``null``, use ``php.ini``'s `session.cookie_samesite`_ directive.
+* ``'none'`` (or the ``Symfony\Component\HttpFoundation\Cookie::SAMESITE_NONE`` constant), use it to allow
+  sending of cookies when the HTTP request originated from a different domain
+  (previously this was the default behavior of null, but in newer browsers ``'lax'``
+  would be applied when the header has not been set)
+* ``'strict'`` (or the ``Cookie::SAMESITE_STRICT`` constant), use it to never
+  send any cookie when the HTTP request did not originate from the same domain.
+* ``'lax'`` (or the ``Cookie::SAMESITE_LAX`` constant), use it to allow sending
+  cookies when the request originated from a different domain, but only when the
+  user consciously made the request (by clicking a link or submitting a form
+  with the ``GET`` method).
 
-    The ``loose`` default value is deprecated since Symfony 6.2. Starting from
-    Symfony 7.0, the default value of this option will be ``html5``.
+cookie_secure
+.............
 
-Sets the default value for the
-:ref:`"mode" option of the Email validator <reference-constraint-email-mode>`.
+**type**: ``boolean`` or ``'auto'``
 
-.. _reference-validation-mapping:
+This determines whether cookies should only be sent over secure connections. In
+addition to ``true`` and ``false``, there's a special ``'auto'`` value that
+means ``true`` for HTTPS requests and ``false`` for HTTP requests.
 
-mapping
-.......
+If not set, ``php.ini``'s `session.cookie_secure`_ directive will be relied on.
 
-.. _reference-validation-mapping-paths:
+.. _reference-session-enabled:
 
-paths
-"""""
+enabled
+.......
 
-**type**: ``array`` **default**: ``['config/validation/']``
+**type**: ``boolean`` **default**: ``true``
 
-This option allows to define an array of paths with files or directories where
-the component will look for additional validation files:
+Whether to enable the session support in the framework.
 
 .. configuration-block::
 
@@ -2885,10 +3092,8 @@ the component will look for additional validation files:
 
         # config/packages/framework.yaml
         framework:
-            validation:
-                mapping:
-                    paths:
-                        - "%kernel.project_dir%/config/validation/"
+            session:
+                enabled: true
 
     .. code-block:: xml
 
@@ -2902,11 +3107,7 @@ the component will look for additional validation files:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:validation>
-                    <framework:mapping>
-                        <framework:path>%kernel.project_dir%/config/validation/</framework:path>
-                    </framework:mapping>
-                </framework:validation>
+                <framework:session enabled="true"/>
             </framework:config>
         </container>
 
@@ -2916,164 +3117,163 @@ the component will look for additional validation files:
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->validation()
-                ->mapping()
-                    ->paths(['%kernel.project_dir%/config/validation/']);
+            $framework->session()
+                ->enabled(true);
         };
 
-annotations
-~~~~~~~~~~~
-
-.. _reference-annotations-cache:
-
-cache
-.....
+gc_divisor
+..........
 
-**type**: ``string`` **default**: ``php_array``
+**type**: ``integer``
 
-This option can be one of the following values:
+See `gc_probability`_.
 
-php_array
-    Use a PHP array to cache annotations in memory
-file
-    Use the filesystem to cache annotations
-none
-    Disable the caching of annotations
+If not set, ``php.ini``'s `session.gc_divisor`_ directive will be relied on.
 
-file_cache_dir
+gc_maxlifetime
 ..............
 
-**type**: ``string`` **default**: ``%kernel.cache_dir%/annotations``
-
-The directory to store cache files for annotations, in case
-``annotations.cache`` is set to ``'file'``.
-
-debug
-.....
-
-**type**: ``boolean`` **default**: ``%kernel.debug%``
-
-Whether to enable debug mode for caching. If enabled, the cache will
-automatically update when the original file is changed (both with code and
-annotation changes). For performance reasons, it is recommended to disable
-debug mode in production, which will happen automatically if you use the
-default value.
-
-.. _configuration-framework-serializer:
-
-serializer
-~~~~~~~~~~
-
-.. _reference-serializer-enabled:
-
-enabled
-.......
-
-**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
-
-Whether to enable the ``serializer`` service or not in the service container.
+**type**: ``integer``
 
-.. _reference-serializer-enable_annotations:
+This determines the number of seconds after which data will be seen as "garbage"
+and potentially cleaned up. Garbage collection may occur during session
+start and depends on `gc_divisor`_ and `gc_probability`_.
 
-enable_annotations
-..................
+If not set, ``php.ini``'s `session.gc_maxlifetime`_ directive will be relied on.
 
-**type**: ``boolean`` **default**: ``true``
+gc_probability
+..............
 
-Enables support for annotations or attributes in the serializer component.
+**type**: ``integer``
 
-.. deprecated:: 6.4
+This defines the probability that the garbage collector (GC) process is
+started on every session initialization. The probability is calculated by
+using ``gc_probability`` / ``gc_divisor``, e.g. 1/100 means there is a 1%
+chance that the GC process will start on each request.
 
-    This option is deprecated since Symfony 6.4, use the ``enable_attributes``
-    option instead.
+If not set, Symfony will use the value of the `session.gc_probability`_ directive
+in the ``php.ini`` configuration file.
 
-enable_attributes
-.................
+.. versionadded:: 7.2
 
-**type**: ``boolean`` **default**: ``true``
+    Relying on ``php.ini``'s directive as default for ``gc_probability`` was
+    introduced in Symfony 7.2.
 
-Enables support for `PHP attributes`_ in the serializer component.
+.. _config-framework-session-handler-id:
 
-.. seealso::
+handler_id
+..........
 
-    See :ref:`the reference <reference-attributes-serializer>` for a list of supported annotations.
+**type**: ``string`` | ``null`` **default**: ``null``
 
-.. _reference-serializer-name_converter:
+If ``framework.session.save_path`` is not set, the default value of this option
+is ``null``, which means to use the session handler configured in php.ini. If the
+``framework.session.save_path`` option is set, then Symfony stores sessions using
+the native file session handler.
 
-name_converter
-..............
+It is possible to :ref:`store sessions in a database <session-database>`,
+and also to configure the session handler with a DSN:
 
-**type**: ``string``
+.. configuration-block::
 
-The name converter to use.
-The :class:`Symfony\\Component\\Serializer\\NameConverter\\CamelCaseToSnakeCaseNameConverter`
-name converter can enabled by using the ``serializer.name_converter.camel_case_to_snake_case``
-value.
+    .. code-block:: yaml
 
-.. seealso::
+        # config/packages/framework.yaml
+        framework:
+            session:
+                # a few possible examples
+                handler_id: 'redis://localhost'
+                handler_id: '%env(REDIS_URL)%'
+                handler_id: '%env(DATABASE_URL)%'
+                handler_id: 'file://%kernel.project_dir%/var/sessions'
 
-    For more information, see :ref:`serializer-name-conversion`.
+    .. code-block:: xml
 
-.. _reference-serializer-circular_reference_handler:
+        <!-- config/packages/framework.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+            <framework:config>
+                <!-- a few possible examples -->
+                <framework:session enabled="true"
+                    handler-id="redis://localhost"
+                    handler-id="%env(REDIS_URL)%"
+                    handler-id="%env(DATABASE_URL)%"
+                    handler-id="file://%kernel.project_dir%/var/sessions"/>
+            </framework:config>
+        </container>
 
-circular_reference_handler
-..........................
+    .. code-block:: php
 
-**type** ``string``
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
+        use function Symfony\Component\DependencyInjection\Loader\Configurator\env;
 
-The service id that is used as the circular reference handler of the default
-serializer. The service has to implement the magic ``__invoke($object)``
-method.
+        return static function (FrameworkConfig $framework): void {
+            // ...
 
-.. seealso::
+            $framework->session()
+                // a few possible examples
+                ->handlerId('redis://localhost')
+                ->handlerId(env('REDIS_URL'))
+                ->handlerId(env('DATABASE_URL'))
+                ->handlerId('file://%kernel.project_dir%/var/sessions');
+        };
 
-    For more information, see
-    :ref:`component-serializer-handling-circular-references`.
+.. note::
 
-.. _reference-serializer-mapping:
+    Supported DSN protocols are the following:
 
-mapping
-.......
+    * ``file``
+    * ``redis``
+    * ``rediss`` (Redis over TLS)
+    * ``memcached`` (requires :doc:`symfony/cache </components/cache>`)
+    * ``pdo_oci`` (requires :doc:`doctrine/dbal </doctrine/dbal>`)
+    * ``mssql``
+    * ``mysql``
+    * ``mysql2``
+    * ``pgsql``
+    * ``postgres``
+    * ``postgresql``
+    * ``sqlsrv``
+    * ``sqlite``
+    * ``sqlite3``
 
-.. _reference-serializer-mapping-paths:
+.. _reference-session-metadata-update-threshold:
 
-paths
-"""""
+metadata_update_threshold
+.........................
 
-**type**: ``array`` **default**: ``[]``
+**type**: ``integer`` **default**: ``0``
 
-This option allows to define an array of paths with files or directories where
-the component will look for additional serialization files.
+This is how many seconds to wait between updating/writing the session metadata.
+This can be useful if, for some reason, you want to limit the frequency at which
+the session persists, instead of doing that on every request.
 
-default_context
-...............
+.. _name:
 
-**type**: ``array`` **default**: ``[]``
+name
+....
 
-A map with default context options that will be used with each ``serialize`` and ``deserialize``
-call. This can be used for example to set the json encoding behavior by setting ``json_encode_options``
-to a `json_encode flags bitmask`_.
+**type**: ``string``
 
-You can inspect the :ref:`serializer context builders <serializer-using-context-builders>`
-to discover the available settings.
+This specifies the name of the session cookie.
 
-php_errors
-~~~~~~~~~~
+If not set, ``php.ini``'s `session.name`_ directive will be relied on.
 
-log
-...
+save_path
+.........
 
-**type**: ``boolean``, ``int`` or ``array<int, string>`` **default**: ``%kernel.debug%``
+**type**: ``string`` | ``null`` **default**: ``%kernel.cache_dir%/sessions``
 
-Use the application logger instead of the PHP logger for logging PHP errors.
-When an integer value is used, it defines a bitmask of PHP errors that will
-be logged. Those integer values must be the same used in the
-`error_reporting PHP option`_. The default log levels will be used for each
-PHP error.
-When a boolean value is used, ``true`` enables logging for all PHP errors
-while ``false`` disables logging entirely.
+This determines the argument to be passed to the save handler. If you choose
+the default file handler, this is the path where the session files are created.
 
-This option also accepts a map of PHP errors to log levels:
+If ``null``, ``php.ini``'s `session.save_path`_ directive will be relied on:
 
 .. configuration-block::
 
@@ -3081,23 +3281,8 @@ This option also accepts a map of PHP errors to log levels:
 
         # config/packages/framework.yaml
         framework:
-            php_errors:
-                log:
-                    !php/const \E_DEPRECATED: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_USER_DEPRECATED: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_NOTICE: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_USER_NOTICE: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_STRICT: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_WARNING: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_USER_WARNING: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_COMPILE_WARNING: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_CORE_WARNING: !php/const Psr\Log\LogLevel::ERROR
-                    !php/const \E_USER_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
-                    !php/const \E_RECOVERABLE_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
-                    !php/const \E_COMPILE_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
-                    !php/const \E_PARSE: !php/const Psr\Log\LogLevel::CRITICAL
-                    !php/const \E_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
-                    !php/const \E_CORE_ERROR: !php/const Psr\Log\LogLevel::CRITICAL
+            session:
+                save_path: ~
 
     .. code-block:: xml
 
@@ -3111,322 +3296,267 @@ This option also accepts a map of PHP errors to log levels:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <!-- in XML configuration you cannot use PHP constants as the value of
-                     the 'type' attribute, which makes this format way less readable.
-                     Consider using YAML or PHP for this configuration -->
-                <framework:log type="8" logLevel="error"/>
-                <framework:log type="2" logLevel="error"/>
-                <!-- ... -->
+                <framework:session save-path="null"/>
             </framework:config>
         </container>
 
     .. code-block:: php
 
         // config/packages/framework.php
-        use Psr\Log\LogLevel;
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->phpErrors()->log(\E_DEPRECATED, LogLevel::ERROR);
-            $framework->phpErrors()->log(\E_USER_DEPRECATED, LogLevel::ERROR);
-            // ...
+            $framework->session()
+                ->savePath(null);
         };
 
-throw
-.....
-
-**type**: ``boolean`` **default**: ``%kernel.debug%``
-
-Throw PHP errors as ``\ErrorException`` instances. The parameter
-``debug.error_handler.throw_at`` controls the threshold.
-
-.. _reference-cache:
-
-cache
-~~~~~
-
-.. _reference-cache-app:
-
-app
-...
-
-**type**: ``string`` **default**: ``cache.adapter.filesystem``
+sid_bits_per_character
+......................
 
-The cache adapter used by the ``cache.app`` service. The FrameworkBundle
-ships with multiple adapters: ``cache.adapter.apcu``, ``cache.adapter.system``,
-``cache.adapter.filesystem``, ``cache.adapter.psr6``, ``cache.adapter.redis``,
-``cache.adapter.memcached``, ``cache.adapter.pdo`` and
-``cache.adapter.doctrine_dbal``.
+**type**: ``integer``
 
-There's also a special adapter called ``cache.adapter.array`` which stores
-contents in memory using a PHP array and it's used to disable caching (mostly on
-the ``dev`` environment).
+This determines the number of bits in the encoded session ID character. The possible
+values are ``4`` (0-9, a-f), ``5`` (0-9, a-v), and ``6`` (0-9, a-z, A-Z, "-", ",").
+The more bits results in stronger session ID. ``5`` is recommended value for
+most environments.
 
-.. tip::
+If not set, ``php.ini``'s `session.sid_bits_per_character`_ directive will be relied on.
 
-    It might be tough to understand at the beginning, so to avoid confusion
-    remember that all pools perform the same actions but on different medium
-    given the adapter they are based on. Internally, a pool wraps the definition
-    of an adapter.
+.. deprecated:: 7.2
 
-.. _reference-cache-system:
+    The ``sid_bits_per_character`` option was deprecated in Symfony 7.2. No alternative
+    is provided as PHP 8.4 has deprecated the related option.
 
-system
-......
+sid_length
+..........
 
-**type**: ``string`` **default**: ``cache.adapter.system``
+**type**: ``integer``
 
-The cache adapter used by the ``cache.system`` service. It supports the same
-adapters available for the ``cache.app`` service.
+This determines the length of session ID string, which can be an integer between
+``22`` and ``256`` (both inclusive), ``32`` being the recommended value. Longer
+session IDs are harder to guess.
 
-directory
-.........
+If not set, ``php.ini``'s `session.sid_length`_ directive will be relied on.
 
-**type**: ``string`` **default**: ``%kernel.cache_dir%/pools``
+.. deprecated:: 7.2
 
-The path to the cache directory used by services inheriting from the
-``cache.adapter.filesystem`` adapter (including ``cache.app``).
+    The ``sid_length`` option was deprecated in Symfony 7.2. No alternative is
+    provided as PHP 8.4 has deprecated the related option.
 
-default_doctrine_provider
-.........................
+.. _storage_id:
 
-**type**: ``string``
+storage_factory_id
+..................
 
-The service name to use as your default Doctrine provider. The provider is
-available as the ``cache.default_doctrine_provider`` service.
+**type**: ``string`` **default**: ``session.storage.factory.native``
 
-default_psr6_provider
-.....................
+The service ID used for creating the ``SessionStorageInterface`` that stores
+the session. This service is available in the Symfony application via the
+``session.storage.factory`` service alias. The class has to implement
+:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageFactoryInterface`.
+To see a list of all available storages, run:
 
-**type**: ``string``
+.. code-block:: terminal
 
-The service name to use as your default PSR-6 provider. It is available as
-the ``cache.default_psr6_provider`` service.
+    $ php bin/console debug:container session.storage.factory.
 
-default_redis_provider
-......................
+use_cookies
+...........
 
-**type**: ``string`` **default**: ``redis://localhost``
+**type**: ``boolean``
 
-The DSN to use by the Redis provider. The provider is available as the ``cache.default_redis_provider``
-service.
+This specifies if the session ID is stored on the client side using cookies or
+not.
 
-default_memcached_provider
-..........................
+If not set, ``php.ini``'s `session.use_cookies`_ directive will be relied on.
 
-**type**: ``string`` **default**: ``memcached://localhost``
+ssi
+~~~
 
-The DSN to use by the Memcached provider. The provider is available as the ``cache.default_memcached_provider``
-service.
+enabled
+.......
 
-default_pdo_provider
-....................
+**type**: ``boolean`` **default**: ``false``
 
-**type**: ``string`` **default**: ``doctrine.dbal.default_connection``
+Whether to enable or not SSI support in your application.
 
-The service id of the database connection, which should be either a PDO or a
-Doctrine DBAL instance. The provider is available as the ``cache.default_pdo_provider``
-service.
+.. _reference-framework-test:
 
-pools
-.....
+test
+~~~~
 
-**type**: ``array``
+**type**: ``boolean``
 
-A list of cache pools to be created by the framework extension.
+If this configuration setting is present (and not ``false``), then the services
+related to testing your application (e.g. ``test.client``) are loaded. This
+setting should be present in your ``test`` environment (usually via
+``config/packages/test/framework.yaml``).
 
 .. seealso::
 
-    For more information about how pools work, see :ref:`cache pools <component-cache-cache-pools>`.
-
-To configure a Redis cache pool with a default lifetime of 1 hour, do the following:
-
-.. configuration-block::
-
-    .. code-block:: yaml
-
-        # config/packages/framework.yaml
-        framework:
-            cache:
-                pools:
-                    cache.mycache:
-                        adapter: cache.adapter.redis
-                        default_lifetime: 3600
-
-    .. code-block:: xml
-
-        <!-- config/packages/framework.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+    For more information, see :doc:`/testing`.
 
-            <framework:config>
-                <framework:cache>
-                    <framework:pool
-                        name="cache.mycache"
-                        adapter="cache.adapter.redis"
-                        default-lifetime="3600"
-                    />
-                </framework:cache>
-                <!-- ... -->
-            </framework:config>
-        </container>
+translator
+~~~~~~~~~~
 
-    .. code-block:: php
+cache_dir
+.........
 
-        // config/packages/framework.php
-        use Symfony\Config\FrameworkConfig;
+**type**: ``string`` | ``null`` **default**: ``%kernel.cache_dir%/translations``
 
-        return static function (FrameworkConfig $framework): void {
-            $framework->cache()
-                ->pool('cache.mycache')
-                    ->adapters(['cache.adapter.redis'])
-                    ->defaultLifetime(3600);
-        };
+Defines the directory where the translation cache is stored. Use ``null`` to
+disable this cache.
 
-.. _reference-cache-pools-name:
+.. _reference-translator-default_path:
 
-name
-""""
+default_path
+............
 
-**type**: ``prototype``
+**type**: ``string`` **default**: ``%kernel.project_dir%/translations``
 
-Name of the pool you want to create.
+This option allows to define the path where the application translations files
+are stored.
 
-.. note::
+.. _reference-translator-enabled:
 
-    Your pool name must differ from ``cache.app`` or ``cache.system``.
+enabled
+.......
 
-adapter
-"""""""
+**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
 
-**type**: ``string`` **default**: ``cache.app``
+Whether or not to enable the ``translator`` service in the service container.
 
-The service name of the adapter to use. You can specify one of the default
-services that follow the pattern ``cache.adapter.[type]``. Alternatively you
-can specify another cache pool as base, which will make this pool inherit the
-settings from the base pool as defaults.
+.. _fallback:
 
-.. note::
+fallbacks
+.........
 
-    Your service needs to implement the ``Psr\Cache\CacheItemPoolInterface`` interface.
+**type**: ``string|array`` **default**: value of `default_locale`_
 
-public
-""""""
+This option is used when the translation key for the current locale wasn't
+found.
 
-**type**: ``boolean`` **default**: ``false``
+.. seealso::
 
-Whether your service should be public or not.
+    For more details, see :doc:`/translation`.
 
-tags
-""""
+.. _reference-framework-translator-formatter:
 
-**type**: ``boolean`` | ``string`` **default**: ``null``
+formatter
+.........
 
-Whether your service should be able to handle tags or not.
-Can also be the service id of another cache pool where tags will be stored.
+**type**: ``string`` **default**: ``translator.formatter.default``
 
-default_lifetime
-""""""""""""""""
+The ID of the service used to format translation messages. The service class
+must implement the :class:`Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface`.
 
-**type**: ``integer`` | ``string``
+.. _reference-framework-translator-logging:
 
-Default lifetime of your cache items. Give an integer value to set the default
-lifetime in seconds. A string value could be ISO 8601 time interval, like ``"PT5M"``
-or a PHP date expression that is accepted by ``strtotime()``, like ``"5 minutes"``.
+logging
+.......
 
-If no value is provided, the cache adapter will fallback to the default value on
-the actual cache storage.
+**default**: ``true`` when the debug mode is enabled, ``false`` otherwise.
 
-provider
-""""""""
+When ``true``, a log entry is made whenever the translator cannot find a translation
+for a given key. The logs are made to the ``translation`` channel at the
+``debug`` level for keys where there is a translation in the fallback
+locale, and the ``warning`` level if there is no translation to use at all.
 
-**type**: ``string``
+.. _reference-translator-paths:
 
-Overwrite the default service name or DSN respectively, if you do not want to
-use what is configured as ``default_X_provider`` under ``cache``. See the
-description of the default provider setting above for information on how to
-specify your specific provider.
+paths
+.....
 
-clearer
-"""""""
+**type**: ``array`` **default**: ``[]``
 
-**type**: ``string``
+This option allows to define an array of paths where the component will look
+for translation files. The later a path is added, the more priority it has
+(translations from later paths overwrite earlier ones). Translations from the
+:ref:`default_path <reference-translator-default_path>` have more priority than
+translations from all these paths.
 
-The cache clearer used to clear your PSR-6 cache.
+.. _reference-translator-providers:
 
-.. seealso::
+providers
+.........
 
-    For more information, see :class:`Symfony\\Component\\HttpKernel\\CacheClearer\\Psr6CacheClearer`.
+**type**: ``array`` **default**: ``[]``
 
-.. _reference-cache-prefix-seed:
+This option enables and configures :ref:`translation providers <translation-providers>`
+to push and pull your translations to/from third party translation services.
 
-prefix_seed
-...........
+trust_x_sendfile_type_header
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-**type**: ``string`` **default**: ``_%kernel.project_dir%.%kernel.container_class%``
+**type**: ``boolean`` **default**: ``%env(bool:default::SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER)%``
 
-This value is used as part of the "namespace" generated for the
-cache item keys. A common practice is to use the unique name of the application
-(e.g. ``symfony.com``) because that prevents naming collisions when deploying
-multiple applications into the same path (on different servers) that share the
-same cache backend.
+.. versionadded:: 7.2
 
-It's also useful when using `blue/green deployment`_ strategies and more
-generally, when you need to abstract out the actual deployment directory (for
-example, when warming caches offline).
+    In Symfony 7.2, the default value of this option was changed from ``false`` to the
+    value stored in the ``SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER`` environment variable.
 
-.. note::
+``X-Sendfile`` is a special HTTP header that tells web servers to replace the
+response contents by the file that is defined in that header. This improves
+performance because files are no longer served by your application but directly
+by the web server.
 
-    The ``prefix_seed`` option is used at compile time. This means
-    that any change made to this value after container's compilation
-    will have no effect.
+This configuration option determines whether to trust ``x-sendfile`` header for
+BinaryFileResponse. If enabled, Symfony calls the
+:method:`BinaryFileResponse::trustXSendfileTypeHeader <Symfony\\Component\\HttpFoundation\\BinaryFileResponse::trustXSendfileTypeHeader>`
+method automatically. It becomes the service container parameter named
+``kernel.trust_x_sendfile_type_header``.
 
-.. _reference-lock:
+.. _reference-framework-trusted-headers:
 
-lock
-~~~~
+trusted_headers
+~~~~~~~~~~~~~~~
 
-**type**: ``string`` | ``array``
+The ``trusted_headers`` option is needed to configure which client information
+should be trusted (e.g. their host) when running Symfony behind a load balancer
+or a reverse proxy. See :doc:`/deployment/proxies`.
 
-The default lock adapter. If not defined, the value is set to ``semaphore`` when
-available, or to ``flock`` otherwise. Store's DSN are also allowed.
+.. _configuration-framework-trusted-hosts:
 
-.. _reference-lock-enabled:
+trusted_hosts
+~~~~~~~~~~~~~
 
-enabled
-.......
+**type**: ``array`` | ``string`` **default**: ``['%env(default::SYMFONY_TRUSTED_HOSTS)%']``
 
-**type**: ``boolean`` **default**: ``true``
+.. versionadded:: 7.2
 
-Whether to enable the support for lock or not. This setting is
-automatically set to ``true`` when one of the child settings is configured.
+    In Symfony 7.2, the default value of this option was changed from ``[]`` to the
+    value stored in the ``SYMFONY_TRUSTED_HOSTS`` environment variable.
 
-.. _reference-lock-resources:
+A lot of different attacks have been discovered relying on inconsistencies
+in handling the ``Host`` header by various software (web servers, reverse
+proxies, web frameworks, etc.). Basically, every time the framework is
+generating an absolute URL (when sending an email to reset a password for
+instance), the host might have been manipulated by an attacker.
 
-resources
-.........
+.. seealso::
 
-**type**: ``array``
+    You can read `HTTP Host header attacks`_ for more information about
+    these kinds of attacks.
 
-A map of lock stores to be created by the framework extension, with
-the name as key and DSN as value:
+The Symfony :method:`Request::getHost() <Symfony\\Component\\HttpFoundation\\Request::getHost>`
+method might be vulnerable to some of these attacks because it depends on
+the configuration of your web server. One simple solution to avoid these
+attacks is to configure a list of hosts that your Symfony application can respond
+to. That's the purpose of this ``trusted_hosts`` option. If the incoming
+request's hostname doesn't match one of the regular expressions in this list,
+the application won't respond and the user will receive a 400 response.
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/lock.yaml
+        # config/packages/framework.yaml
         framework:
-            lock: '%env(LOCK_DSN)%'
+            trusted_hosts:  ['^example\.com$', '^example\.org$']
 
     .. code-block:: xml
 
-        <!-- config/packages/lock.xml -->
+        <!-- config/packages/framework.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -3436,77 +3566,76 @@ the name as key and DSN as value:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:lock>
-                    <framework:resource name="default">%env(LOCK_DSN)%</framework:resource>
-                </framework:lock>
+                <framework:trusted-host>^example\.com$</framework:trusted-host>
+                <framework:trusted-host>^example\.org$</framework:trusted-host>
+                <!-- ... -->
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/lock.php
+        // config/packages/framework.php
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->lock()
-                ->resource('default', [env('LOCK_DSN')]);
+            $framework->trustedHosts(['^example\.com$', '^example\.org$']);
         };
 
-.. seealso::
-
-    For more details, see :doc:`/lock`.
-
-.. _reference-lock-resources-name:
-
-name
-""""
-
-**type**: ``prototype``
+Hosts can also be configured to respond to any subdomain, via
+``^(.+\.)?example\.com$`` for instance.
 
-Name of the lock you want to create.
+In addition, you can also set the trusted hosts in the front controller
+using the ``Request::setTrustedHosts()`` method::
 
-semaphore
-~~~~~~~~~
+    // public/index.php
+    Request::setTrustedHosts(['^(.+\.)?example\.com$', '^(.+\.)?example\.org$']);
 
-.. versionadded:: 6.1
+The default value for this option is an empty array, meaning that the application
+can respond to any given host.
 
-    The ``semaphore`` option was introduced in Symfony 6.1.
+.. seealso::
 
-**type**: ``string`` | ``array``
+    Read more about this in the `Security Advisory Blog post`_.
 
-The default semaphore adapter. Store's DSN are also allowed.
+.. _reference-framework-trusted-proxies:
 
-.. _reference-semaphore-enabled:
+trusted_proxies
+~~~~~~~~~~~~~~~
 
-enabled
-.......
+The ``trusted_proxies`` option is needed to get precise information about the
+client (e.g. their IP address) when running Symfony behind a load balancer or a
+reverse proxy. See :doc:`/deployment/proxies`.
 
-**type**: ``boolean`` **default**: ``true``
+.. _reference-validation:
 
-Whether to enable the support for semaphore or not. This setting is
-automatically set to ``true`` when one of the child settings is configured.
+validation
+~~~~~~~~~~
 
-.. _reference-semaphore-resources:
+.. _reference-validation-auto-mapping:
 
-resources
-.........
+auto_mapping
+............
 
-**type**: ``array``
+**type**: ``array`` **default**: ``[]``
 
-A map of semaphore stores to be created by the framework extension, with
-the name as key and DSN as value:
+Defines the Doctrine entities that will be introspected to add
+:ref:`automatic validation constraints <automatic_object_validation>` to them:
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/semaphore.yaml
         framework:
-            semaphore: '%env(SEMAPHORE_DSN)%'
+            validation:
+                auto_mapping:
+                    # an empty array means that all entities that belong to that
+                    # namespace will add automatic validation
+                    'App\Entity\': []
+                    'Foo\': ['Foo\Some\Entity', 'Foo\Another\Entity']
 
     .. code-block:: xml
 
-        <!-- config/packages/semaphore.xml -->
+        <!-- config/packages/framework.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -3516,93 +3645,107 @@ the name as key and DSN as value:
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
             <framework:config>
-                <framework:semaphore>
-                    <framework:resource name="default">%env(SEMAPHORE_DSN)%</framework:resource>
-                </framework:semaphore>
+                <framework:validation>
+                    <framework:auto-mapping>
+                        <framework:service namespace="App\Entity\"/>
+
+                        <framework:service namespace="Foo\">Foo\Some\Entity</framework:service>
+                        <framework:service namespace="Foo\">Foo\Another\Entity</framework:service>
+                    </framework:auto-mapping>
+                </framework:validation>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/semaphore.php
+        // config/packages/framework.php
         use Symfony\Config\FrameworkConfig;
 
         return static function (FrameworkConfig $framework): void {
-            $framework->semaphore()
-                ->resource('default', ['%env(SEMAPHORE_DSN)%']);
+            $framework->validation()
+                ->autoMapping()
+                    ->paths([
+                        'App\\Entity\\' => [],
+                        'Foo\\' => ['Foo\\Some\\Entity', 'Foo\\Another\\Entity'],
+                    ]);
         };
 
-.. _reference-semaphore-resources-name:
+.. _reference-validation-disable_translation:
 
-name
-""""
+disable_translation
+...................
 
-**type**: ``prototype``
+**type**: ``boolean`` **default**: ``false``
+
+Validation error messages are automatically translated to the current application
+locale. Set this option to ``true`` to disable translation of validation messages.
+This is useful to avoid "missing translation" errors in applications that use
+only a single language.
+
+.. versionadded:: 7.3
+
+    The ``disable_translation`` option was introduced in Symfony 7.3.
 
-Name of the semaphore you want to create.
+.. _reference-validation-email_validation_mode:
 
-mailer
-~~~~~~
+email_validation_mode
+.....................
 
-.. _mailer-dsn:
+**type**: ``string`` **default**: ``html5``
 
-dsn
-...
+Sets the default value for the
+:ref:`"mode" option of the Email validator <reference-constraint-email-mode>`.
 
-**type**: ``string`` **default**: ``null``
+.. _reference-validation-enable_annotations:
 
-The DSN used by the mailer. When several DSN may be used, use
-``transports`` option (see below) instead.
+enable_attributes
+.................
 
-transports
-..........
+**type**: ``boolean`` **default**: ``true``
 
-**type**: ``array``
+If this option is enabled, validation constraints can be defined using `PHP attributes`_.
 
-A :ref:`list of DSN <multiple-email-transports>` that can be used by the
-mailer. A transport name is the key and the dsn is the value.
+.. _reference-validation-enabled:
 
-message_bus
-...........
+enabled
+.......
 
-**type**: ``string`` **default**: ``null`` or default bus if Messenger component is installed
+**type**: ``boolean`` **default**: ``true`` or ``false`` depending on your installation
 
-Service identifier of the message bus to use when using the
-:doc:`Messenger component </messenger>` (e.g. ``messenger.default_bus``).
+Whether or not to enable validation support.
 
-envelope
-........
+This option will automatically be set to ``true`` when one of the child
+settings is configured.
 
-sender
-""""""
+.. _reference-validation-mapping:
 
-**type**: ``string``
+mapping
+.......
 
-The "envelope sender" which is used as the value of ``MAIL FROM`` during the
-`SMTP session`_. This value overrides any other sender set in the code.
+.. _reference-validation-mapping-paths:
 
-recipients
-""""""""""
+paths
+"""""
 
-**type**: ``array``
+**type**: ``array`` **default**: ``['config/validation/']``
 
-The "envelope recipient" which is used as the value of ``RCPT TO`` during the
-the `SMTP session`_. This value overrides any other recipient set in the code.
+This option allows to define an array of paths with files or directories where
+the component will look for additional validation files:
 
 .. configuration-block::
 
     .. code-block:: yaml
 
-        # config/packages/mailer.yaml
+        # config/packages/framework.yaml
         framework:
-            mailer:
-                dsn: 'smtp://localhost:25'
-                envelope:
-                    recipients: ['admin@symfony.com', 'lead@symfony.com']
+            validation:
+                mapping:
+                    paths:
+                        - "%kernel.project_dir%/config/validation/"
 
     .. code-block:: xml
 
-        <!-- config/packages/mailer.xml -->
+        <!-- config/packages/framework.xml -->
         <?xml version="1.0" encoding="UTF-8" ?>
         <container xmlns="http://symfony.com/schema/dic/services"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -3610,63 +3753,77 @@ the `SMTP session`_. This value overrides any other recipient set in the code.
             xsi:schemaLocation="http://symfony.com/schema/dic/services
                 https://symfony.com/schema/dic/services/services-1.0.xsd
                 http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
             <framework:config>
-                <framework:mailer dsn="smtp://localhost:25">
-                    <framework:envelope>
-                        <framework:recipient>admin@symfony.com</framework:recipient>
-                        <framework:recipient>lead@symfony.com</framework:recipient>
-                    </framework:envelope>
-                </framework:mailer>
+                <framework:validation>
+                    <framework:mapping>
+                        <framework:path>%kernel.project_dir%/config/validation/</framework:path>
+                    </framework:mapping>
+                </framework:validation>
             </framework:config>
         </container>
 
     .. code-block:: php
 
-        // config/packages/mailer.php
-        namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+        // config/packages/framework.php
+        use Symfony\Config\FrameworkConfig;
 
-        return static function (ContainerConfigurator $container): void {
-            $container->extension('framework', [
-                'mailer' => [
-                    'dsn' => 'smtp://localhost:25',
-                    'envelope' => [
-                        'recipients' => [
-                            'admin@symfony.com',
-                            'lead@symfony.com',
-                        ],
-                    ],
-                ],
-            ]);
+        return static function (FrameworkConfig $framework): void {
+            $framework->validation()
+                ->mapping()
+                    ->paths(['%kernel.project_dir%/config/validation/']);
         };
 
-.. _mailer-headers:
+.. _reference-validation-not-compromised-password:
 
-headers
-.......
+not_compromised_password
+........................
 
-**type**: ``array``
+The :doc:`NotCompromisedPassword </reference/constraints/NotCompromisedPassword>`
+constraint makes HTTP requests to a public API to check if the given password
+has been compromised in a data breach.
 
-Headers to add to emails. The key (``name`` attribute in xml format) is the
-header name and value the header value.
+static_method
+.............
 
-.. seealso::
+**type**: ``string | array`` **default**: ``['loadValidatorMetadata']``
 
-    For more information, see :ref:`Configuring Emails Globally <mailer-configure-email-globally>`
+Defines the name of the static method which is called to load the validation
+metadata of the class. You can define an array of strings with the names of
+several methods. In that case, all of them will be called in that order to load
+the metadata.
 
-messenger
-~~~~~~~~~
+translation_domain
+..................
+
+**type**: ``string | false`` **default**: ``validators``
+
+The translation domain that is used when translating validation constraint
+error messages. Use false to disable translations.
+
+
+.. _reference-validation-not-compromised-password-enabled:
 
 enabled
-.......
+"""""""
 
 **type**: ``boolean`` **default**: ``true``
 
-Whether to enable or not Messenger.
+If you set this option to ``false``, no HTTP requests will be made and the given
+password will be considered valid. This is useful when you don't want or can't
+make HTTP requests, such as in ``dev`` and ``test`` environments or in
+continuous integration servers.
 
-.. seealso::
+endpoint
+""""""""
 
-    For more details, see the :doc:`Messenger component </messenger>`
-    documentation.
+**type**: ``string`` **default**: ``null``
+
+By default, the :doc:`NotCompromisedPassword </reference/constraints/NotCompromisedPassword>`
+constraint uses the public API provided by `haveibeenpwned.com`_. This option
+allows to define a different, but compatible, API endpoint to make the password
+checks. It's useful for example when the Symfony application is run in an
+intranet without public access to the internet.
 
 web_link
 ~~~~~~~~
@@ -3681,10 +3838,6 @@ Adds a `Link HTTP header`_ to the response.
 webhook
 ~~~~~~~
 
-.. versionadded:: 6.3
-
-    The Webhook configuration was introduced in Symfony 6.3.
-
 The ``webhook`` option (and its children) are used to configure the webhooks
 defined in your application. Read more about the options in the :ref:`Webhook documentation <webhook>`.
 
@@ -3842,113 +3995,6 @@ Defines the kind of workflow that is going to be created, which can be either
 a normal workflow or a state machine. Read :doc:`this article </workflow/workflow-and-state-machine>`
 to know their differences.
 
-.. _framework_exceptions:
-
-exceptions
-~~~~~~~~~~
-
-**type**: ``array``
-
-Defines the :ref:`log level </logging>` and HTTP status code applied to the
-exceptions that match the given exception class:
-
-.. configuration-block::
-
-    .. code-block:: yaml
-
-        # config/packages/exceptions.yaml
-        framework:
-            exceptions:
-                Symfony\Component\HttpKernel\Exception\BadRequestHttpException:
-                    log_level: 'debug'
-                    status_code: 422
-
-    .. code-block:: xml
-
-        <!-- config/packages/exceptions.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <container xmlns="http://symfony.com/schema/dic/services"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xmlns:framework="http://symfony.com/schema/dic/symfony"
-            xsi:schemaLocation="http://symfony.com/schema/dic/services
-                https://symfony.com/schema/dic/services/services-1.0.xsd
-                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
-
-            <framework:config>
-                <framework:exception
-                    class="Symfony\Component\HttpKernel\Exception\BadRequestHttpException"
-                    log-level="debug"
-                    status-code="422"
-                />
-                <!-- ... -->
-            </framework:config>
-        </container>
-
-    .. code-block:: php
-
-        // config/packages/exceptions.php
-        use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
-        use Symfony\Config\FrameworkConfig;
-
-        return static function (FrameworkConfig $framework): void {
-            $framework->exception(BadRequestHttpException::class)
-                ->logLevel('debug')
-                ->statusCode(422)
-            ;
-        };
-
-The order in which you configure exceptions is important because Symfony will
-use the configuration of the first exception that matches ``instanceof``:
-
-.. code-block:: yaml
-
-        # config/packages/exceptions.yaml
-        framework:
-            exceptions:
-                Exception:
-                    log_level: 'debug'
-                    status_code: 404
-                # The following configuration will never be used because \RuntimeException extends \Exception
-                RuntimeException:
-                    log_level: 'debug'
-                    status_code: 422
-
-You can map a status code and a set of headers to an exception thanks
-to the ``#[WithHttpStatus]`` attribute on the exception class::
-
-    namespace App\Exception;
-
-    use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
-
-    #[WithHttpStatus(422, [
-       'Retry-After' => 10,
-       'X-Custom-Header' => 'header-value',
-    ])]
-    class CustomException extends \Exception
-    {
-    }
-
-.. versionadded:: 6.3
-
-    The ``#[WithHttpStatus]`` attribute was introduced in Symfony 6.3.
-
-It is also possible to map a log level on a custom exception class using
-the ``#[WithLogLevel]`` attribute::
-
-    namespace App\Exception;
-
-    use Psr\Log\LogLevel;
-    use Symfony\Component\HttpKernel\Attribute\WithLogLevel;
-
-    #[WithLogLevel(LogLevel::WARNING)]
-    class CustomException extends \Exception
-    {
-    }
-
-.. versionadded:: 6.3
-
-    The ``#[WithLogLevel]`` attribute was introduced in Symfony 6.3.
-
 .. _`HTTP Host header attacks`: https://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html
 .. _`Security Advisory Blog post`: https://symfony.com/blog/security-releases-symfony-2-0-24-2-1-12-2-2-5-and-2-3-3-released#cve-2013-4752-request-gethost-poisoning
 .. _`phpstorm-url-handler`: https://github.com/sanduhrs/phpstorm-url-handler
@@ -3971,6 +4017,7 @@ the ``#[WithLogLevel]`` attribute::
 .. _`session.cookie_samesite`: https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-samesite
 .. _`session.cookie_secure`: https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-secure
 .. _`session.gc_divisor`: https://www.php.net/manual/en/session.configuration.php#ini.session.gc-divisor
+.. _`session.gc_probability`: https://www.php.net/manual/en/session.configuration.php#ini.session.gc-probability
 .. _`session.gc_maxlifetime`: https://www.php.net/manual/en/session.configuration.php#ini.session.gc-maxlifetime
 .. _`session.sid_length`: https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length
 .. _`session.sid_bits_per_character`: https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character
diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst
index e12482aae4a..b7596182906 100644
--- a/reference/configuration/kernel.rst
+++ b/reference/configuration/kernel.rst
@@ -25,11 +25,6 @@ method of the kernel class, which you can override to return a different value.
 You can also change the build directory by defining an environment variable
 named ``APP_BUILD_DIR`` whose value is the absolute path of the build folder.
 
-.. versionadded:: 6.4
-
-    The support of the ``APP_BUILD_DIR`` environment variable was introduced in
-    Symfony 6.4.
-
 ``kernel.bundles``
 ------------------
 
@@ -321,10 +316,6 @@ the application is running in web mode and ``web=1&worker=1`` when running in
 a long-running web server. This parameter can be set by using the
 ``APP_RUNTIME_MODE`` env var.
 
-.. versionadded:: 6.4
-
-    The ``kernel.runtime_mode`` parameter was introduced in Symfony 6.4.
-
 ``kernel.runtime_mode.web``
 ---------------------------
 
@@ -332,10 +323,6 @@ a long-running web server. This parameter can be set by using the
 
 Whether the application is running in a web environment.
 
-.. versionadded:: 6.4
-
-    The ``kernel.runtime_mode.web`` parameter was introduced in Symfony 6.4.
-
 ``kernel.runtime_mode.cli``
 ---------------------------
 
@@ -344,10 +331,6 @@ Whether the application is running in a web environment.
 Whether the application is running in a CLI environment. By default,
 this value is the opposite of the ``kernel.runtime_mode.web`` parameter.
 
-.. versionadded:: 6.4
-
-    The ``kernel.runtime_mode.cli`` parameter was introduced in Symfony 6.4.
-
 ``kernel.runtime_mode.worker``
 ------------------------------
 
@@ -356,10 +339,6 @@ this value is the opposite of the ``kernel.runtime_mode.web`` parameter.
 Whether the application is running in a worker/long-running environment. Not all web
 servers support it, and you have to use a long-running web server like `FrankenPHP`_.
 
-.. versionadded:: 6.4
-
-    The ``kernel.runtime_mode.worker`` parameter was introduced in Symfony 6.4.
-
 ``kernel.secret``
 -----------------
 
diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst
index 3ccea5f9026..ef7247e330e 100644
--- a/reference/configuration/security.rst
+++ b/reference/configuration/security.rst
@@ -23,7 +23,8 @@ key in your application configuration.
 
 * `access_denied_url`_
 * `erase_credentials`_
-* `hide_user_not_found`_
+* `expose_security_errors`_
+* `hide_user_not_found`_ (deprecated)
 * `session_fixation_strategy`_
 
 **Advanced Options**:
@@ -51,13 +52,59 @@ erase_credentials
 **type**: ``boolean`` **default**: ``true``
 
 If ``true``, the ``eraseCredentials()`` method of the user object is called
-after authentication.
+after authentication::
+
+    use Symfony\Component\Security\Core\User\UserInterface;
+
+    class User implements UserInterface
+    {
+        // ...
+
+        public function eraseCredentials(): void
+        {
+            // If you store any temporary, sensitive data on the user, clear it here
+            // $this->plainPassword = null;
+        }
+    }
+
+.. deprecated:: 7.3
+
+   Since Symfony 7.3, ``eraseCredentials()`` methods are deprecated and are
+   not called if they have the ``#[\Deprecated]`` attribute.
+
+expose_security_errors
+----------------------
+
+**type**: ``string`` **default**: ``'none'``
+
+.. versionadded:: 7.3
+
+    The ``expose_security_errors`` option was introduced in Symfony 7.3
+
+User enumeration is a common security issue where attackers infer valid usernames
+based on error messages. For example, a message like "This user does not exist"
+shown by your login form reveals whether a username exists.
+
+This option lets you hide some or all errors related to user accounts
+(e.g. blocked or expired accounts) to prevent this issue. Instead, these
+errors will trigger a generic ``BadCredentialsException``. The value of this
+option can be one of the following:
+
+* ``'none'``: hides all user-related security exceptions;
+* ``'account_status'``: shows account-related exceptions (e.g. blocked or expired
+  accounts) but only for users who provided the correct password;
+* ``'all'``: shows all security-related exceptions.
 
 hide_user_not_found
 -------------------
 
 **type**: ``boolean`` **default**: ``true``
 
+.. deprecated:: 7.3
+
+    The ``hide_user_not_found`` option was deprecated in favor of the
+    ``expose_security_errors`` option in Symfony 7.3.
+
 If ``true``, when a user is not found a generic exception of type
 :class:`Symfony\\Component\\Security\\Core\\Exception\\BadCredentialsException`
 is thrown with the message "Bad credentials".
@@ -486,10 +533,6 @@ It's also possible to use ``*`` as a wildcard for all directives:
                     ->clearSiteData(['cookies', 'storage']);
         };
 
-.. versionadded:: 6.3
-
-    The ``clear_site_data`` option was introduced in Symfony 6.3.
-
 invalidate_session
 ..................
 
@@ -530,10 +573,6 @@ Set this option to ``true`` to enable CSRF protection in the logout process
 using Symfony's default CSRF token manager. Set also the ``csrf_token_manager``
 option if you need to use a custom CSRF token manager.
 
-.. versionadded:: 6.2
-
-    The ``enable_csrf`` option was introduced in Symfony 6.2.
-
 csrf_parameter
 ..............
 
@@ -796,10 +835,6 @@ user_identifier
 
 **type**: ``string`` **default**: ``emailAddress``
 
-.. versionadded:: 6.3
-
-    The ``user_identifier`` option was introduced in Symfony 6.3.
-
 The value of this option tells Symfony which parameter to use to find the user
 identifier in the "distinguished name".
 
diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst
index bec117cc609..360309fef8f 100644
--- a/reference/configuration/twig.rst
+++ b/reference/configuration/twig.rst
@@ -30,44 +30,13 @@ compiled again automatically.
 
 .. _config-twig-autoescape:
 
-autoescape
-~~~~~~~~~~
-
-.. deprecated:: 6.1
-
-    This option is deprecated since Symfony 6.1. If required, use the
-    ``autoescape_service`` or ``autoescape_service_method`` option instead.
-
-**type**: ``boolean`` or ``string`` **default**: ``name``
-
-If set to ``false``, automatic escaping is disabled (you can still escape each content
-individually in the templates).
-
-.. danger::
-
-    Setting this option to ``false`` is dangerous and it will make your
-    application vulnerable to :ref:`XSS attacks <xss-attacks>` because most
-    third-party bundles assume that auto-escaping is enabled and they don't
-    escape contents themselves.
-
-If set to a string, the template contents are escaped using the strategy with
-that name. Allowed values are ``html``, ``js``, ``css``, ``url``, ``html_attr``
-and ``name``. The default value is ``name``. This strategy escapes contents
-according to the template name extension (e.g. it uses ``html`` for ``*.html.twig``
-templates and ``js`` for ``*.js.twig`` templates).
-
-.. tip::
-
-    See `autoescape_service`_ and `autoescape_service_method`_ to define your
-    own escaping strategy.
-
 autoescape_service
 ~~~~~~~~~~~~~~~~~~
 
 **type**: ``string`` **default**: ``null``
 
-The escaping strategy applied by default to the template is determined during
-compilation time based on the filename of the template. This means for example
+The escaping strategy applied by default to the template (to prevent :ref:`XSS attacks <xss-attacks>`)
+is determined during compilation time based on the filename of the template. This means for example
 that the contents of a ``*.html.twig`` template are escaped for HTML and the
 contents of ``*.js.twig`` are escaped for JavaScript.
 
@@ -85,16 +54,15 @@ called to determine the default escaping applied to the template.
 If the service defined in ``autoescape_service`` is invocable (i.e. it defines
 the `__invoke() PHP magic method`_) you can omit this option.
 
-.. versionadded:: 6.4
-
-    The feature to use invocable services to omit this option was introduced in
-    Symfony 6.4.
-
 base_template_class
 ~~~~~~~~~~~~~~~~~~~
 
 **type**: ``string`` **default**: ``Twig\Template``
 
+.. deprecated:: 7.1
+
+    The ``base_template_class`` option is deprecated since Symfony 7.1.
+
 Twig templates are compiled into PHP classes before using them to render
 contents. This option defines the base class from which all the template classes
 extend. Using a custom base template is discouraged because it will make your
@@ -103,16 +71,27 @@ application harder to maintain.
 cache
 ~~~~~
 
-**type**: ``string`` | ``false`` **default**: ``%kernel.cache_dir%/twig``
+**type**: ``string`` | ``boolean`` **default**: ``true``
 
 Before using the Twig templates to render some contents, they are compiled into
 regular PHP code. Compilation is a costly process, so the result is cached in
 the directory defined by this configuration option.
 
+You can either specify a custom path where the cache should be stored (as a
+string) or use ``true`` to let Symfony decide the default path. When set to
+``true``, the cache is stored in ``%kernel.cache_dir%/twig`` by default. However,
+if ``auto_reload`` is disabled and ``%kernel.build_dir%`` differs from
+``%kernel.cache_dir%``, the cache will be stored in ``%kernel.build_dir%/twig`` instead.
+
 Set this option to ``false`` to disable Twig template compilation. However, this
-is not recommended; not even in the ``dev`` environment, because the
-``auto_reload`` option ensures that cached templates which have changed get
-compiled again.
+is not recommended, not even in the ``dev`` environment, because the ``auto_reload``
+option ensures that cached templates which have changed get compiled again.
+
+.. versionadded:: 7.3
+
+    Support for using ``true`` as a value was introduced in Symfony 7.3. It also
+    became the default value for this option, replacing the explicit path
+    ``%kernel.cache_dir%/twig``.
 
 charset
 ~~~~~~~
@@ -183,10 +162,6 @@ file_name_pattern
 
 **type**: ``string`` or ``array`` of ``string`` **default**: ``[]``
 
-.. versionadded:: 6.1
-
-    The ``file_name_pattern`` option was introduced in Symfony 6.1.
-
 Some applications store their front-end assets in the same directory as Twig
 templates. The ``lint:twig`` command filters those files to only lint the ones
 that match the ``*.twig`` filename pattern.
@@ -317,10 +292,6 @@ html_to_text_converter
 
 **type**: ``string`` **default**: ``null``
 
-.. versionadded:: 6.2
-
-    The ``html_to_text_converter`` option was introduced in Symfony 6.2.
-
 The service implementing
 :class:`Symfony\\Component\\Mime\\HtmlToTextConverter\\HtmlToTextConverterInterface`
 that will be used to automatically create the text part of an email from its
diff --git a/reference/configuration/web_profiler.rst b/reference/configuration/web_profiler.rst
index de706c73fef..c3b57d37c55 100644
--- a/reference/configuration/web_profiler.rst
+++ b/reference/configuration/web_profiler.rst
@@ -53,8 +53,21 @@ on the given link to perform the redirect.
 toolbar
 ~~~~~~~
 
+enabled
+.......
 **type**: ``boolean`` **default**: ``false``
 
 It enables and disables the toolbar entirely. Usually you set this to ``true``
 in the ``dev`` and ``test`` environments and to ``false`` in the ``prod``
 environment.
+
+ajax_replace
+............
+**type**: ``boolean`` **default**: ``false``
+
+If you set this option to ``true``, the toolbar is replaced on AJAX requests.
+This only works in combination with an enabled toolbar.
+
+.. versionadded:: 7.3
+
+    The ``ajax_replace`` configuration option was introduced in Symfony 7.3.
diff --git a/reference/constraints/All.rst b/reference/constraints/All.rst
index 3aa05b1d2d0..43ff4d6ac9d 100644
--- a/reference/constraints/All.rst
+++ b/reference/constraints/All.rst
@@ -79,12 +79,12 @@ entry in that array:
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('favoriteColors', new Assert\All([
-                    'constraints' => [
+                $metadata->addPropertyConstraint('favoriteColors', new Assert\All(
+                    constraints: [
                         new Assert\NotBlank(),
-                        new Assert\Length(['min' => 5]),
+                        new Assert\Length(min: 5),
                     ],
-                ]));
+                ));
             }
         }
 
@@ -97,7 +97,7 @@ Options
 ``constraints``
 ~~~~~~~~~~~~~~~
 
-**type**: ``array`` [:ref:`default option <validation-default-option>`]
+**type**: ``array``
 
 This required option is the array of validation constraints that you want
 to apply to each element of the underlying array.
diff --git a/reference/constraints/AtLeastOneOf.rst b/reference/constraints/AtLeastOneOf.rst
index 0a6ab618aa5..fecbe617f5a 100644
--- a/reference/constraints/AtLeastOneOf.rst
+++ b/reference/constraints/AtLeastOneOf.rst
@@ -115,23 +115,23 @@ The following constraints ensure that:
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('password', new Assert\AtLeastOneOf([
-                    'constraints' => [
-                        new Assert\Regex(['pattern' => '/#/']),
-                        new Assert\Length(['min' => 10]),
+                $metadata->addPropertyConstraint('password', new Assert\AtLeastOneOf(
+                    constraints: [
+                        new Assert\Regex(pattern: '/#/'),
+                        new Assert\Length(min: 10),
                     ],
-                ]));
+                ));
 
-                $metadata->addPropertyConstraint('grades', new Assert\AtLeastOneOf([
-                    'constraints' => [
-                        new Assert\Count(['min' => 3]),
-                        new Assert\All([
-                            'constraints' => [
+                $metadata->addPropertyConstraint('grades', new Assert\AtLeastOneOf(
+                    constraints: [
+                        new Assert\Count(min: 3),
+                        new Assert\All(
+                            constraints: [
                                 new Assert\GreaterThanOrEqual(5),
                             ],
-                        ]),
+                        ),
                     ],
-                ]));
+                ));
             }
         }
 
@@ -141,7 +141,7 @@ Options
 constraints
 ~~~~~~~~~~~
 
-**type**: ``array`` [:ref:`default option <validation-default-option>`]
+**type**: ``array``
 
 This required option is the array of validation constraints from which at least one of
 has to be satisfied in order for the validation to succeed.
diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst
index 69ce35248f3..6cde4a11bac 100644
--- a/reference/constraints/Bic.rst
+++ b/reference/constraints/Bic.rst
@@ -121,4 +121,19 @@ Parameter        Description
 
 .. include:: /reference/constraints/_payload-option.rst.inc
 
+``mode``
+~~~~~~~~
+
+**type**: ``string`` **default**: ``Bic::VALIDATION_MODE_STRICT``
+
+This option defines how the BIC is validated. The possible values are available
+as constants in the :class:`Symfony\\Component\\Validator\\Constraints\\Bic` class:
+
+* ``Bic::VALIDATION_MODE_STRICT`` validates the given value without any modification;
+* ``Bic::VALIDATION_MODE_CASE_INSENSITIVE`` converts the given value to uppercase before validating it.
+
+.. versionadded:: 7.2
+
+    The ``mode`` option was introduced in Symfony 7.2.
+
 .. _`Business Identifier Code (BIC)`: https://en.wikipedia.org/wiki/Business_Identifier_Code
diff --git a/reference/constraints/Callback.rst b/reference/constraints/Callback.rst
index f4c78a9642a..017b9435cff 100644
--- a/reference/constraints/Callback.rst
+++ b/reference/constraints/Callback.rst
@@ -259,7 +259,7 @@ Options
 ``callback``
 ~~~~~~~~~~~~
 
-**type**: ``string``, ``array`` or ``Closure`` [:ref:`default option <validation-default-option>`]
+**type**: ``string``, ``array`` or ``Closure``
 
 The callback option accepts three different formats for specifying the
 callback method:
diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst
index 6e98e6fab98..a2ed9c568c3 100644
--- a/reference/constraints/CardScheme.rst
+++ b/reference/constraints/CardScheme.rst
@@ -77,12 +77,12 @@ on an object that will contain a credit card number.
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('cardNumber', new Assert\CardScheme([
-                    'schemes' => [
+                $metadata->addPropertyConstraint('cardNumber', new Assert\CardScheme(
+                    schemes: [
                         Assert\CardScheme::VISA,
                     ],
-                    'message' => 'Your credit card number is invalid.',
-                ]));
+                    message: 'Your credit card number is invalid.',
+                ));
             }
         }
 
@@ -114,7 +114,7 @@ Parameter        Description
 ``schemes``
 ~~~~~~~~~~~
 
-**type**: ``mixed`` [:ref:`default option <validation-default-option>`]
+**type**: ``mixed``
 
 This option is required and represents the name of the number scheme used
 to validate the credit card number, it can either be a string or an array.
diff --git a/reference/constraints/Cascade.rst b/reference/constraints/Cascade.rst
index bd6050add0b..3c99f423b0f 100644
--- a/reference/constraints/Cascade.rst
+++ b/reference/constraints/Cascade.rst
@@ -95,8 +95,4 @@ The ``groups`` option is not available for this constraint.
 This option can be used to exclude one or more properties from the
 cascade validation.
 
-.. versionadded:: 6.3
-
-    The ``exclude`` option was introduced in Symfony 6.3.
-
 .. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/Charset.rst b/reference/constraints/Charset.rst
new file mode 100644
index 00000000000..084f24cdf76
--- /dev/null
+++ b/reference/constraints/Charset.rst
@@ -0,0 +1,113 @@
+Charset
+=======
+
+.. versionadded:: 7.1
+
+    The ``Charset`` constraint was introduced in Symfony 7.1.
+
+Validates that a string (or an object implementing the ``Stringable`` PHP interface)
+is encoded in a given charset.
+
+==========  =====================================================================
+Applies to  :ref:`property or method <validation-property-target>`
+Class       :class:`Symfony\\Component\\Validator\\Constraints\\Charset`
+Validator   :class:`Symfony\\Component\\Validator\\Constraints\\CharsetValidator`
+==========  =====================================================================
+
+Basic Usage
+-----------
+
+If you wanted to ensure that the ``content`` property of a ``FileDTO``
+class uses UTF-8, you could do the following:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/FileDTO.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+
+        class FileDTO
+        {
+            #[Assert\Charset('UTF-8')]
+            protected string $content;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\FileDTO:
+            properties:
+                content:
+                    - Charset: 'UTF-8'
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\FileDTO">
+                <property name="content">
+                    <constraint name="Charset">
+                        <option name="charset">UTF-8</option>
+                    </constraint>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/FileDTO.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class FileDTO
+        {
+            // ...
+
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('content', new Assert\Charset('UTF-8'));
+            }
+        }
+
+Options
+-------
+
+``encodings``
+~~~~~~~~~~~~~
+
+**type**: ``array`` | ``string`` **default**: ``[]``
+
+An encoding or a set of encodings to check against. If you pass an array of
+encodings, the validator will check if the value is encoded in *any* of the
+encodings. This option accepts any value that can be passed to the
+:phpfunction:`mb_detect_encoding` PHP function.
+
+.. include:: /reference/constraints/_groups-option.rst.inc
+
+``message``
+~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}.``
+
+This is the message that will be shown if the value does not match any of the
+accepted encodings.
+
+You can use the following parameters in this message:
+
+===================  ==============================================================
+Parameter            Description
+===================  ==============================================================
+``{{ detected }}``   The detected encoding
+``{{ encodings }}``  The accepted encodings
+===================  ==============================================================
+
+.. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst
index cb1738eb7a6..72e1ae6ecf7 100644
--- a/reference/constraints/Choice.rst
+++ b/reference/constraints/Choice.rst
@@ -100,10 +100,10 @@ If your valid choice list is simple, you can pass them in directly via the
                     new Assert\Choice(['New York', 'Berlin', 'Tokyo'])
                 );
 
-                $metadata->addPropertyConstraint('genre', new Assert\Choice([
-                    'choices' => ['fiction', 'non-fiction'],
-                    'message' => 'Choose a valid genre.',
-                ]));
+                $metadata->addPropertyConstraint('genre', new Assert\Choice(
+                    choices: ['fiction', 'non-fiction'],
+                    message: 'Choose a valid genre.',
+                ));
             }
         }
 
@@ -182,9 +182,9 @@ constraint.
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('genre', new Assert\Choice([
-                    'callback' => 'getGenres',
-                ]));
+                $metadata->addPropertyConstraint('genre', new Assert\Choice(
+                    callback: 'getGenres',
+                ));
             }
         }
 
@@ -250,9 +250,9 @@ you can pass the class name and the method as an array.
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('genre', new Assert\Choice([
-                    'callback' => [Genre::class, 'getGenres'],
-                ]));
+                $metadata->addPropertyConstraint('genre', new Assert\Choice(
+                    callback: [Genre::class, 'getGenres'],
+                ));
             }
         }
 
@@ -271,7 +271,7 @@ to return the choices array. See
 ``choices``
 ~~~~~~~~~~~
 
-**type**: ``array`` [:ref:`default option <validation-default-option>`]
+**type**: ``array``
 
 A required option (unless `callback`_ is specified) - this is the array
 of options that should be considered in the valid set. The input value
@@ -316,10 +316,6 @@ When this option is ``false``, the constraint checks that the given value is
 not one of the values defined in the ``choices`` option. In practice, it makes
 the ``Choice`` constraint behave like a ``NotChoice`` constraint.
 
-.. versionadded:: 6.2
-
-    The ``match`` option was introduced in Symfony 6.2.
-
 ``message``
 ~~~~~~~~~~~
 
diff --git a/reference/constraints/Cidr.rst b/reference/constraints/Cidr.rst
index d5c52e74b2a..78a5b6c7167 100644
--- a/reference/constraints/Cidr.rst
+++ b/reference/constraints/Cidr.rst
@@ -124,10 +124,18 @@ Parameter        Description
 **type**: ``string`` **default**: ``all``
 
 This determines exactly *how* the CIDR notation is validated and can take one
-of these values:
+of :ref:`IP version ranges <reference-constraint-ip-version>`.
 
-* ``4``: validates for CIDR notations that have an IPv4;
-* ``6``: validates for CIDR notations that have an IPv6;
-* ``all``: validates all CIDR formats.
+.. note::
+
+    The IP range checks (e.g., ``*_private``, ``*_reserved``) validate only the
+    IP address, not the entire netmask. To improve validation, you can set the
+    ``{{ min }}`` value for the netmask. For example, the range ``9.0.0.0/6`` is
+    considered ``*_public``, but it also includes the ``10.0.0.0/8`` range, which
+    is categorized as ``*_private``.
+
+.. versionadded:: 7.1
+
+    The support of all IP version ranges was introduced in Symfony 7.1.
 
 .. _`CIDR`: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst
index 2d16d201b17..c35a0103581 100644
--- a/reference/constraints/Collection.rst
+++ b/reference/constraints/Collection.rst
@@ -139,8 +139,8 @@ following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('profileData', new Assert\Collection([
-                    'fields' => [
+                $metadata->addPropertyConstraint('profileData', new Assert\Collection(
+                    fields: [
                         'personal_email' => new Assert\Email(),
                         'short_bio' => [
                             new Assert\NotBlank(),
@@ -150,8 +150,8 @@ following:
                             ]),
                         ],
                     ],
-                    'allowMissingFields' => true,
-                ]));
+                    allowMissingFields: true,
+                ));
             }
         }
 
@@ -267,15 +267,15 @@ you can do the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('profileData', new Assert\Collection([
-                    'fields' => [
+                $metadata->addPropertyConstraint('profileData', new Assert\Collection(
+                    fields: [
                         'personal_email'  => new Assert\Required([
                             new Assert\NotBlank(),
                             new Assert\Email(),
                         ]),
                         'alternate_email' => new Assert\Optional(new Assert\Email()),
                     ],
-                ]));
+                ));
             }
         }
 
@@ -291,28 +291,28 @@ groups. Take the following example::
 
     use Symfony\Component\Validator\Constraints as Assert;
 
-    $constraint = new Assert\Collection([
-        'fields' => [
+    $constraint = new Assert\Collection(
+        fields: [
             'name' => new Assert\NotBlank(['groups' => 'basic']),
             'email' => new Assert\NotBlank(['groups' => 'contact']),
         ],
-    ]);
+    );
 
 This will result in the following configuration::
 
-    $constraint = new Assert\Collection([
-        'fields' => [
-            'name' => new Assert\Required([
-                'constraints' => new Assert\NotBlank(['groups' => 'basic']),
-                'groups' => ['basic', 'strict'],
-            ]),
-            'email' => new Assert\Required([
-                "constraints" => new Assert\NotBlank(['groups' => 'contact']),
-                'groups' => ['basic', 'strict'],
-            ]),
+    $constraint = new Assert\Collection(
+        fields: [
+            'name' => new Assert\Required(
+                constraints: new Assert\NotBlank(groups: ['basic']),
+                groups: ['basic', 'strict'],
+            ),
+            'email' => new Assert\Required(
+                constraints: new Assert\NotBlank(groups: ['contact']),
+                groups: ['basic', 'strict'],
+            ),
         ],
-        'groups' => ['basic', 'strict'],
-    ]);
+        groups: ['basic', 'strict'],
+    );
 
 The default ``allowMissingFields`` option requires the fields in all groups.
 So when validating in ``contact`` group, ``$name`` can be empty but the key is
@@ -360,7 +360,7 @@ Parameter        Description
 ``fields``
 ~~~~~~~~~~
 
-**type**: ``array`` [:ref:`default option <validation-default-option>`]
+**type**: ``array``
 
 This option is required and is an associative array defining all of the
 keys in the collection and, for each key, exactly which validator(s) should
diff --git a/reference/constraints/Compound.rst b/reference/constraints/Compound.rst
index fc8081f5917..4d2c7743176 100644
--- a/reference/constraints/Compound.rst
+++ b/reference/constraints/Compound.rst
@@ -35,9 +35,9 @@ you can create your own named set or requirements to be reused consistently ever
                 return [
                     new Assert\NotBlank(),
                     new Assert\Type('string'),
-                    new Assert\Length(['min' => 12]),
+                    new Assert\Length(min: 12),
                     new Assert\NotCompromisedPassword(),
-                    new Assert\PasswordStrength(['minScore' => 4]),
+                    new Assert\PasswordStrength(minScore: 4),
                 ];
             }
         }
@@ -102,6 +102,50 @@ You can now use it anywhere you need it:
             }
         }
 
+Validation groups and payload can be passed via constructor:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/User.php
+        namespace App\Entity\User;
+
+        use App\Validator\Constraints as Assert;
+
+        class User
+        {
+            #[Assert\PasswordRequirements(
+                groups: ['registration'],
+                payload: ['severity' => 'error'],
+            )]
+            public string $plainPassword;
+        }
+
+    .. code-block:: php
+
+        // src/Entity/User.php
+        namespace App\Entity\User;
+
+        use App\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class User
+        {
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('plainPassword', new Assert\PasswordRequirements(
+                    groups: ['registration'],
+                    payload: ['severity' => 'error'],
+                ));
+            }
+        }
+
+.. versionadded:: 7.2
+
+    Support for passing validation groups and the payload to the constructor
+    of the ``Compound`` class was introduced in Symfony 7.2.
+
 Options
 -------
 
diff --git a/reference/constraints/Count.rst b/reference/constraints/Count.rst
index 0bf40aca8e9..d33c54c0812 100644
--- a/reference/constraints/Count.rst
+++ b/reference/constraints/Count.rst
@@ -82,12 +82,12 @@ you might add the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('emails', new Assert\Count([
-                    'min' => 1,
-                    'max' => 5,
-                    'minMessage' => 'You must specify at least one email',
-                    'maxMessage' => 'You cannot specify more than {{ limit }} emails',
-                ]));
+                $metadata->addPropertyConstraint('emails', new Assert\Count(
+                    min: 1,
+                    max: 5,
+                    minMessage: 'You must specify at least one email',
+                    maxMessage: 'You cannot specify more than {{ limit }} emails',
+                ));
             }
         }
 
diff --git a/reference/constraints/CssColor.rst b/reference/constraints/CssColor.rst
index fbbc982087d..b9c78ec25ac 100644
--- a/reference/constraints/CssColor.rst
+++ b/reference/constraints/CssColor.rst
@@ -110,15 +110,15 @@ the named CSS colors:
             {
                 $metadata->addPropertyConstraint('defaultColor', new Assert\CssColor());
 
-                $metadata->addPropertyConstraint('accentColor', new Assert\CssColor([
-                    'formats' => Assert\CssColor::HEX_LONG,
-                    'message' => 'The accent color must be a 6-character hexadecimal color.',
-                ]));
-
-                $metadata->addPropertyConstraint('currentColor', new Assert\CssColor([
-                    'formats' => [Assert\CssColor::BASIC_NAMED_COLORS, Assert\CssColor::EXTENDED_NAMED_COLORS],
-                    'message' => 'The color "{{ value }}" is not a valid CSS color name.',
-                ]));
+                $metadata->addPropertyConstraint('accentColor', new Assert\CssColor(
+                    formats: Assert\CssColor::HEX_LONG,
+                    message: 'The accent color must be a 6-character hexadecimal color.',
+                ));
+
+                $metadata->addPropertyConstraint('currentColor', new Assert\CssColor(
+                    formats: [Assert\CssColor::BASIC_NAMED_COLORS, Assert\CssColor::EXTENDED_NAMED_COLORS],
+                    message: 'The color "{{ value }}" is not a valid CSS color name.',
+                ));
             }
         }
 
diff --git a/reference/constraints/DateTime.rst b/reference/constraints/DateTime.rst
index f6bcce7e5f5..ffcfbf55dda 100644
--- a/reference/constraints/DateTime.rst
+++ b/reference/constraints/DateTime.rst
@@ -99,11 +99,16 @@ This message is shown if the underlying data is not a valid datetime.
 
 You can use the following parameters in this message:
 
-===============  ==============================================================
-Parameter        Description
-===============  ==============================================================
-``{{ value }}``  The current (invalid) value
-``{{ label }}``  Corresponding form field label
-===============  ==============================================================
+================  ==============================================================
+Parameter         Description
+================  ==============================================================
+``{{ value }}``   The current (invalid) value
+``{{ label }}``   Corresponding form field label
+``{{ format }}``  The date format defined in ``format``
+================  ==============================================================
+
+.. versionadded:: 7.3
+
+    The ``{{ format }}`` parameter was introduced in Symfony 7.3.
 
 .. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/DivisibleBy.rst b/reference/constraints/DivisibleBy.rst
index dd90ad9a0fd..23b36023cff 100644
--- a/reference/constraints/DivisibleBy.rst
+++ b/reference/constraints/DivisibleBy.rst
@@ -92,9 +92,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('weight', new Assert\DivisibleBy(0.25));
 
-                $metadata->addPropertyConstraint('quantity', new Assert\DivisibleBy([
-                    'value' => 5,
-                ]));
+                $metadata->addPropertyConstraint('quantity', new Assert\DivisibleBy(
+                    value: 5,
+                ));
             }
         }
 
diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst
index 19b1579b88a..41012e5e935 100644
--- a/reference/constraints/Email.rst
+++ b/reference/constraints/Email.rst
@@ -70,9 +70,9 @@ Basic Usage
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('email', new Assert\Email([
-                    'message' => 'The email "{{ value }}" is not a valid email.',
-                ]));
+                $metadata->addPropertyConstraint('email', new Assert\Email(
+                    message: 'The email "{{ value }}" is not a valid email.',
+                ));
             }
         }
 
@@ -104,13 +104,10 @@ Parameter        Description
 ``mode``
 ~~~~~~~~
 
-**type**: ``string`` **default**: (see below)
+**type**: ``string`` **default**: ``html5``
 
 This option defines the pattern used to validate the email address. Valid values are:
 
-* ``loose`` uses a simple regular expression (just checks that at least one ``@``
-  character is present, etc.). This validation is too simple and it's recommended
-  to use one of the other modes instead;
 * ``html5`` uses the regular expression of the `HTML5 email input element`_,
   except it enforces a tld to be present.
 * ``html5-allow-no-tld`` uses exactly the same regular expression as the `HTML5 email input element`_,
@@ -119,10 +116,6 @@ This option defines the pattern used to validate the email address. Valid values
   `egulias/email-validator`_ library (which is already installed when using
   :doc:`Symfony Mailer </mailer>`; otherwise, you must install it separately).
 
-.. versionadded:: 6.2
-
-   The ``html5-allow-no-tld`` mode was introduced in 6.2.
-
 .. tip::
 
     The possible values of this option are also defined as PHP constants of
@@ -133,11 +126,6 @@ The default value used by this option is set in the
 :ref:`framework.validation.email_validation_mode <reference-validation-email_validation_mode>`
 configuration option.
 
-.. deprecated:: 6.2
-
-    The ``loose`` value is deprecated since Symfony 6.2. Starting from
-    Symfony 7.0, the default value of this option will be ``html5``.
-
 .. include:: /reference/constraints/_normalizer-option.rst.inc
 
 .. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/EqualTo.rst b/reference/constraints/EqualTo.rst
index d5d78f60a0f..fdc402b1a97 100644
--- a/reference/constraints/EqualTo.rst
+++ b/reference/constraints/EqualTo.rst
@@ -91,9 +91,9 @@ and that the ``age`` is ``20``, you could do the following:
             {
                 $metadata->addPropertyConstraint('firstName', new Assert\EqualTo('Mary'));
 
-                $metadata->addPropertyConstraint('age', new Assert\EqualTo([
-                    'value' => 20,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\EqualTo(
+                    value: 20,
+                ));
             }
         }
 
diff --git a/reference/constraints/Expression.rst b/reference/constraints/Expression.rst
index 1f3b4dcdb7c..518c5c1f160 100644
--- a/reference/constraints/Expression.rst
+++ b/reference/constraints/Expression.rst
@@ -111,10 +111,10 @@ One way to accomplish this is with the Expression constraint:
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addConstraint(new Assert\Expression([
-                    'expression' => 'this.getCategory() in ["php", "symfony"] or !this.isTechnicalPost()',
-                    'message' => 'If this is a tech post, the category should be either php or symfony!',
-                ]));
+                $metadata->addConstraint(new Assert\Expression(
+                    expression: 'this.getCategory() in ["php", "symfony"] or !this.isTechnicalPost()',
+                    message: 'If this is a tech post, the category should be either php or symfony!',
+                ));
             }
 
             // ...
@@ -127,10 +127,6 @@ about the :doc:`expression language syntax </reference/formats/expression_langua
 Alternatively, you can set the ``negate`` option to ``false`` in order to
 assert that the expression must return ``true`` for validation to fail.
 
-.. versionadded:: 6.2
-
-   The ``negate`` option was introduced in Symfony 6.2.
-
 .. sidebar:: Mapping the Error to a Specific Field
 
     You can also attach the constraint to a specific property and still validate
@@ -204,10 +200,10 @@ assert that the expression must return ``true`` for validation to fail.
             {
                 public static function loadValidatorMetadata(ClassMetadata $metadata): void
                 {
-                    $metadata->addPropertyConstraint('isTechnicalPost', new Assert\Expression([
-                        'expression' => 'this.getCategory() in ["php", "symfony"] or value == false',
-                        'message' => 'If this is a tech post, the category should be either php or symfony!',
-                    ]));
+                    $metadata->addPropertyConstraint('isTechnicalPost', new Assert\Expression(
+                        expression: 'this.getCategory() in ["php", "symfony"] or value == false',
+                        message: 'If this is a tech post, the category should be either php or symfony!',
+                    ));
                 }
 
                 // ...
@@ -231,7 +227,7 @@ Options
 ``expression``
 ~~~~~~~~~~~~~~
 
-**type**: ``string`` [:ref:`default option <validation-default-option>`]
+**type**: ``string``
 
 The expression that will be evaluated. If the expression evaluates to a false
 value (using ``==``, not ``===``), validation will fail. Learn more about the
@@ -247,10 +243,6 @@ in your expression:
 You also have access to the ``is_valid()`` function in your expression. This function
 checks that the data passed to function doesn't raise any validation violation.
 
-.. versionadded:: 6.4
-
-    The ``is_valid()`` expression function was introduced in Symfony 6.4.
-
 .. include:: /reference/constraints/_groups-option.rst.inc
 
 ``message``
@@ -276,10 +268,6 @@ Parameter        Description
 
 If ``false``, the validation fails when expression returns ``true``.
 
-.. versionadded:: 6.2
-
-   The ``negate`` option was introduced in Symfony 6.2.
-
 .. include:: /reference/constraints/_payload-option.rst.inc
 
 ``values``
@@ -355,10 +343,10 @@ type (numeric, boolean, strings, null, etc.)
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('metric', new Assert\Expression([
-                    'expression' => 'value + error_margin < threshold',
-                    'values' => ['error_margin' => 0.25, 'threshold' => 1.5],
-                ]));
+                $metadata->addPropertyConstraint('metric', new Assert\Expression(
+                    expression: 'value + error_margin < threshold',
+                    values: ['error_margin' => 0.25, 'threshold' => 1.5],
+                ));
             }
 
             // ...
diff --git a/reference/constraints/ExpressionLanguageSyntax.rst b/reference/constraints/ExpressionLanguageSyntax.rst
deleted file mode 100644
index f10956c4046..00000000000
--- a/reference/constraints/ExpressionLanguageSyntax.rst
+++ /dev/null
@@ -1,127 +0,0 @@
-ExpressionLanguageSyntax
-========================
-
-.. deprecated:: 6.1
-
-    This constraint is deprecated since Symfony 6.1. Instead, use the
-    :doc:`ExpressionSyntax </reference/constraints/ExpressionSyntax>` constraint.
-
-This constraint checks that the value is valid as an `ExpressionLanguage`_
-expression.
-
-==========  ===================================================================
-Applies to  :ref:`property or method <validation-property-target>`
-Class       :class:`Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntax`
-Validator   :class:`Symfony\\Component\\Validator\\Constraints\\ExpressionLanguageSyntaxValidator`
-==========  ===================================================================
-
-Basic Usage
------------
-
-The following constraints ensure that:
-
-* the ``promotion`` property stores a value which is valid as an
-  ExpressionLanguage expression;
-* the ``shippingOptions`` property also ensures that the expression only uses
-  certain variables.
-
-.. configuration-block::
-
-    .. code-block:: php-attributes
-
-        // src/Entity/Order.php
-        namespace App\Entity;
-
-        use Symfony\Component\Validator\Constraints as Assert;
-
-        class Order
-        {
-            #[Assert\ExpressionLanguageSyntax]
-            protected string  $promotion;
-
-            #[Assert\ExpressionLanguageSyntax(
-                allowedVariables: ['user', 'shipping_centers'],
-            )]
-            protected string $shippingOptions;
-        }
-
-    .. code-block:: yaml
-
-        # config/validator/validation.yaml
-        App\Entity\Order:
-            properties:
-                promotion:
-                    - ExpressionLanguageSyntax: ~
-                shippingOptions:
-                    - ExpressionLanguageSyntax:
-                        allowedVariables: ['user', 'shipping_centers']
-
-    .. code-block:: xml
-
-        <!-- config/validator/validation.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
-
-            <class name="App\Entity\Order">
-                <property name="promotion">
-                    <constraint name="ExpressionLanguageSyntax"/>
-                </property>
-                <property name="shippingOptions">
-                    <constraint name="ExpressionLanguageSyntax">
-                        <option name="allowedVariables">
-                            <value>user</value>
-                            <value>shipping_centers</value>
-                        </option>
-                    </constraint>
-                </property>
-            </class>
-        </constraint-mapping>
-
-    .. code-block:: php
-
-        // src/Entity/Student.php
-        namespace App\Entity;
-
-        use Symfony\Component\Validator\Constraints as Assert;
-        use Symfony\Component\Validator\Mapping\ClassMetadata;
-
-        class Order
-        {
-            // ...
-
-            public static function loadValidatorMetadata(ClassMetadata $metadata): void
-            {
-                $metadata->addPropertyConstraint('promotion', new Assert\ExpressionLanguageSyntax());
-
-                $metadata->addPropertyConstraint('shippingOptions', new Assert\ExpressionLanguageSyntax([
-                    'allowedVariables' => ['user', 'shipping_centers'],
-                ]));
-            }
-        }
-
-Options
--------
-
-allowedVariables
-~~~~~~~~~~~~~~~~
-
-**type**: ``array`` or ``null`` **default**: ``null``
-
-If this option is defined, the expression can only use the variables whose names
-are included in this option. Unset this option or set its value to ``null`` to
-allow any variables.
-
-.. include:: /reference/constraints/_groups-option.rst.inc
-
-message
-~~~~~~~
-
-**type**: ``string`` **default**: ``This value should be a valid expression.``
-
-This is the message displayed when the validation fails.
-
-.. include:: /reference/constraints/_payload-option.rst.inc
-
-.. _`ExpressionLanguage`: https://symfony.com/components/ExpressionLanguage
diff --git a/reference/constraints/ExpressionSyntax.rst b/reference/constraints/ExpressionSyntax.rst
index 2a603eaa616..37e0ad7de4a 100644
--- a/reference/constraints/ExpressionSyntax.rst
+++ b/reference/constraints/ExpressionSyntax.rst
@@ -4,12 +4,6 @@ ExpressionSyntax
 This constraint checks that the value is valid as an `ExpressionLanguage`_
 expression.
 
-.. versionadded:: 6.1
-
-    This constraint was introduced in Symfony 6.1 and deprecates the previous
-    :doc:`ExpressionLanguageSyntax </reference/constraints/ExpressionLanguageSyntax>`
-    constraint.
-
 ==========  ===================================================================
 Applies to  :ref:`property or method <validation-property-target>`
 Class       :class:`Symfony\\Component\\Validator\\Constraints\\ExpressionSyntax`
@@ -96,9 +90,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('promotion', new Assert\ExpressionSyntax());
 
-                $metadata->addPropertyConstraint('shippingOptions', new Assert\ExpressionSyntax([
-                    'allowedVariables' => ['user', 'shipping_centers'],
-                ]));
+                $metadata->addPropertyConstraint('shippingOptions', new Assert\ExpressionSyntax(
+                    allowedVariables: ['user', 'shipping_centers'],
+                ));
             }
         }
 
diff --git a/reference/constraints/File.rst b/reference/constraints/File.rst
index 4f8f5beddfc..62efa6cc08e 100644
--- a/reference/constraints/File.rst
+++ b/reference/constraints/File.rst
@@ -119,13 +119,13 @@ below a certain file size and a valid PDF, add the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('bioFile', new Assert\File([
-                    'maxSize' => '1024k',
-                    'extensions' => [
+                $metadata->addPropertyConstraint('bioFile', new Assert\File(
+                    maxSize: '1024k',
+                    extensions: [
                         'pdf',
                     ],
-                    'extensionsMessage' => 'Please upload a valid PDF',
-                ]));
+                    extensionsMessage: 'Please upload a valid PDF',
+                ));
             }
         }
 
@@ -156,10 +156,6 @@ see `Wikipedia: Binary prefix`_.
 
 **type**: ``array`` or ``string``
 
-.. versionadded:: 6.2
-
-    The ``extensions`` option was introduced in Symfony 6.2.
-
 If set, the validator will check that the extension and the media type
 (formerly known as MIME type) of the underlying file are equal to the given
 extension and associated media type (if a string) or exist in the collection
@@ -275,22 +271,39 @@ You can find a list of existing mime types on the `IANA website`_.
 
 **type**: ``integer`` **default**: ``null``
 
-.. versionadded:: 6.3
-
-    The ``filenameMaxLength`` was introduced in Symfony 6.3.
-
 If set, the validator will check that the filename of the underlying file
 doesn't exceed a certain length.
 
+``filenameCountUnit``
+~~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``File::FILENAME_COUNT_BYTES``
+
+The character count unit to use for the filename max length check.
+By default :phpfunction:`strlen` is used, which counts the length of the string in bytes.
+
+Can be one of the following constants of the
+:class:`Symfony\\Component\\Validator\\Constraints\\File` class:
+
+* ``FILENAME_COUNT_BYTES``: Uses :phpfunction:`strlen` counting the length of the
+  string in bytes.
+* ``FILENAME_COUNT_CODEPOINTS``: Uses :phpfunction:`mb_strlen` counting the length
+  of the string in Unicode code points. Simple (multibyte) Unicode characters count
+  as 1 character, while for example ZWJ sequences of composed emojis count as
+  multiple characters.
+* ``FILENAME_COUNT_GRAPHEMES``: Uses :phpfunction:`grapheme_strlen` counting the
+  length of the string in graphemes, i.e. even emojis and ZWJ sequences of composed
+  emojis count as 1 character.
+
+.. versionadded:: 7.3
+
+    The ``filenameCountUnit`` option was introduced in Symfony 7.3.
+
 ``filenameTooLongMessage``
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 **type**: ``string`` **default**: ``The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.``
 
-.. versionadded:: 6.3
-
-    The ``filenameTooLongMessage`` was introduced in Symfony 6.3.
-
 The message displayed if the filename of the file exceeds the limit set
 with the ``filenameMaxLength`` option.
 
@@ -302,15 +315,40 @@ Parameter                       Description
 ``{{ filename_max_length }}``   Maximum number of characters allowed
 ==============================  ==============================================================
 
+``filenameCharset``
+~~~~~~~~~~~~~~~~~~~
+
+**type**: ``string``  **default**: ``null``
+
+The charset to be used when computing value's filename max length with the
+:phpfunction:`mb_check_encoding` and :phpfunction:`mb_strlen`
+PHP functions.
+
+``filenameCharsetMessage``
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This filename does not match the expected charset.``
+
+The message that will be shown if the value is not using the given `filenameCharsetMessage`_.
+
+You can use the following parameters in this message:
+
+=================  ============================================================
+Parameter          Description
+=================  ============================================================
+``{{ charset }}``  The expected charset
+``{{ name }}``     The current (invalid) value
+=================  ============================================================
+
+.. versionadded:: 7.3
+
+    The ``filenameCharset`` and ``filenameCharsetMessage`` options were introduced in Symfony 7.3.
+
 ``extensionsMessage``
 ~~~~~~~~~~~~~~~~~~~~~
 
 **type**: ``string`` **default**: ``The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.``
 
-.. versionadded:: 6.2
-
-    The ``extensionsMessage`` option was introduced in Symfony 6.2.
-
 The message displayed if the extension of the file is not a valid extension
 per the `extensions`_ option.
 
diff --git a/reference/constraints/GreaterThan.rst b/reference/constraints/GreaterThan.rst
index 4f2e34bcbfa..d1b79028acd 100644
--- a/reference/constraints/GreaterThan.rst
+++ b/reference/constraints/GreaterThan.rst
@@ -89,9 +89,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('siblings', new Assert\GreaterThan(5));
 
-                $metadata->addPropertyConstraint('age', new Assert\GreaterThan([
-                    'value' => 18,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\GreaterThan(
+                    value: 18,
+                ));
             }
         }
 
diff --git a/reference/constraints/GreaterThanOrEqual.rst b/reference/constraints/GreaterThanOrEqual.rst
index e5a71e5f788..63c2ade6197 100644
--- a/reference/constraints/GreaterThanOrEqual.rst
+++ b/reference/constraints/GreaterThanOrEqual.rst
@@ -88,9 +88,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('siblings', new Assert\GreaterThanOrEqual(5));
 
-                $metadata->addPropertyConstraint('age', new Assert\GreaterThanOrEqual([
-                    'value' => 18,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\GreaterThanOrEqual(
+                    value: 18,
+                ));
             }
         }
 
diff --git a/reference/constraints/Hostname.rst b/reference/constraints/Hostname.rst
index 95b10d1736e..58ac0364669 100644
--- a/reference/constraints/Hostname.rst
+++ b/reference/constraints/Hostname.rst
@@ -72,9 +72,9 @@ will contain a host name.
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('name', new Assert\Hostname([
-                    'message' => 'The server name must be a valid hostname.',
-                ]));
+                $metadata->addPropertyConstraint('name', new Assert\Hostname(
+                    message: 'The server name must be a valid hostname.',
+                ));
             }
         }
 
diff --git a/reference/constraints/Iban.rst b/reference/constraints/Iban.rst
index 849d93cb565..fdc955c81b0 100644
--- a/reference/constraints/Iban.rst
+++ b/reference/constraints/Iban.rst
@@ -77,9 +77,9 @@ will contain an International Bank Account Number.
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('bankAccountNumber', new Assert\Iban([
-                    'message' => 'This is not a valid International Bank Account Number (IBAN).',
-                ]));
+                $metadata->addPropertyConstraint('bankAccountNumber', new Assert\Iban(
+                    message: 'This is not a valid International Bank Account Number (IBAN).',
+                ));
             }
         }
 
diff --git a/reference/constraints/IdenticalTo.rst b/reference/constraints/IdenticalTo.rst
index 5b6d853dc0b..f8844f90a72 100644
--- a/reference/constraints/IdenticalTo.rst
+++ b/reference/constraints/IdenticalTo.rst
@@ -94,9 +94,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('firstName', new Assert\IdenticalTo('Mary'));
 
-                $metadata->addPropertyConstraint('age', new Assert\IdenticalTo([
-                    'value' => 20,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\IdenticalTo(
+                    value: 20,
+                ));
             }
         }
 
diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst
index 042c6041423..5dd270c44f8 100644
--- a/reference/constraints/Image.rst
+++ b/reference/constraints/Image.rst
@@ -116,12 +116,12 @@ that it is between a certain size, add the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('headshot', new Assert\Image([
-                    'minWidth' => 200,
-                    'maxWidth' => 400,
-                    'minHeight' => 200,
-                    'maxHeight' => 400,
-                ]));
+                $metadata->addPropertyConstraint('headshot', new Assert\Image(
+                    minWidth: 200,
+                    maxWidth: 400,
+                    minHeight: 200,
+                    maxHeight: 400,
+                ));
             }
         }
 
@@ -187,10 +187,10 @@ following code:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('headshot', new Assert\Image([
-                    'allowLandscape' => false,
-                    'allowPortrait' => false,
-                ]));
+                $metadata->addPropertyConstraint('headshot', new Assert\Image(
+                    allowLandscape: false,
+                    allowPortrait: false,
+                ));
             }
         }
 
@@ -210,10 +210,9 @@ add several other options.
 
 If this option is false, the image cannot be landscape oriented.
 
-.. note::
+.. versionadded:: 7.3
 
-    This option does not apply to SVG files. If you use it with SVG files,
-    you'll see the error message defined in the ``sizeNotDetectedMessage`` option.
+    The ``allowLandscape`` option support for SVG files was introduced in Symfony 7.3.
 
 ``allowLandscapeMessage``
 ~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -239,10 +238,9 @@ Parameter         Description
 
 If this option is false, the image cannot be portrait oriented.
 
-.. note::
+.. versionadded:: 7.3
 
-    This option does not apply to SVG files. If you use it with SVG files,
-    you'll see the error message defined in the ``sizeNotDetectedMessage`` option.
+    The ``allowPortrait`` option support for SVG files was introduced in Symfony 7.3.
 
 ``allowPortraitMessage``
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -270,10 +268,9 @@ If this option is false, the image cannot be a square. If you want to force
 a square image, then leave this option as its default ``true`` value
 and set `allowLandscape`_ and `allowPortrait`_ both to ``false``.
 
-.. note::
+.. versionadded:: 7.3
 
-    This option does not apply to SVG files. If you use it with SVG files,
-    you'll see the error message defined in the ``sizeNotDetectedMessage`` option.
+    The ``allowSquare`` option support for SVG files was introduced in Symfony 7.3.
 
 ``allowSquareMessage``
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -373,10 +370,9 @@ Parameter             Description
 If set, the aspect ratio (``width / height``) of the image file must be less
 than or equal to this value.
 
-.. note::
+.. versionadded:: 7.3
 
-    This option does not apply to SVG files. If you use it with SVG files,
-    you'll see the error message defined in the ``sizeNotDetectedMessage`` option.
+    The ``maxRatio`` option support for SVG files was introduced in Symfony 7.3.
 
 ``maxRatioMessage``
 ~~~~~~~~~~~~~~~~~~~
@@ -497,10 +493,9 @@ Parameter             Description
 If set, the aspect ratio (``width / height``) of the image file must be greater
 than or equal to this value.
 
-.. note::
+.. versionadded:: 7.3
 
-    This option does not apply to SVG files. If you use it with SVG files,
-    you'll see the error message defined in the ``sizeNotDetectedMessage`` option.
+    The ``minRatio`` option support for SVG files was introduced in Symfony 7.3.
 
 ``minRatioMessage``
 ~~~~~~~~~~~~~~~~~~~
@@ -555,11 +550,5 @@ options has been set.
 
 This message has no parameters.
 
-.. note::
-
-    Detecting the size of SVG images is not supported. This error message will
-    be displayed if you use any of the following options: ``allowLandscape``,
-    ``allowPortrait``, ``allowSquare``, ``maxRatio``, and ``minRatio``.
-
 .. _`IANA website`: https://www.iana.org/assignments/media-types/media-types.xhtml
 .. _`PHP GD extension`: https://www.php.net/manual/en/book.image.php
diff --git a/reference/constraints/Ip.rst b/reference/constraints/Ip.rst
index 2f05f677601..20cd4400c0a 100644
--- a/reference/constraints/Ip.rst
+++ b/reference/constraints/Ip.rst
@@ -97,46 +97,30 @@ Parameter        Description
 
 .. include:: /reference/constraints/_payload-option.rst.inc
 
+.. _reference-constraint-ip-version:
+
 ``version``
 ~~~~~~~~~~~
 
 **type**: ``string`` **default**: ``4``
 
-This determines exactly *how* the IP address is validated and can take one
-of a variety of different values:
-
-**All ranges**
-
-``4``
-    Validates for IPv4 addresses
-``6``
-    Validates for IPv6 addresses
-``all``
-    Validates all IP formats
-
-**No private ranges**
-
-``4_no_priv``
-    Validates for IPv4 but without private IP ranges
-``6_no_priv``
-    Validates for IPv6 but without private IP ranges
-``all_no_priv``
-    Validates for all IP formats but without private IP ranges
-
-**No reserved ranges**
-
-``4_no_res``
-    Validates for IPv4 but without reserved IP ranges
-``6_no_res``
-    Validates for IPv6 but without reserved IP ranges
-``all_no_res``
-    Validates for all IP formats but without reserved IP ranges
-
-**Only public ranges**
-
-``4_public``
-    Validates for IPv4 but without private and reserved ranges
-``6_public``
-    Validates for IPv6 but without private and reserved ranges
-``all_public``
-    Validates for all IP formats but without private and reserved ranges
+This determines exactly *how* the IP address is validated. This option defines a
+lot of different possible values based on the ranges and the type of IP address
+that you want to allow/deny:
+
+====================  ===================  ===================  ==================
+Ranges Allowed        IPv4 addresses only  IPv6 addresses only  Both IPv4 and IPv6
+====================  ===================  ===================  ==================
+All                   ``4``                ``6``                ``all``
+All except private    ``4_no_priv``        ``6_no_priv``        ``all_no_priv``
+All except reserved   ``4_no_res``         ``6_no_res``         ``all_no_res``
+All except public     ``4_no_public``      ``6_no_public``      ``all_no_public``
+Only private          ``4_private``        ``6_private``        ``all_private``
+Only reserved         ``4_reserved``       ``6_reserved``       ``all_reserved``
+Only public           ``4_public``         ``6_public``         ``all_public``
+====================  ===================  ===================  ==================
+
+.. versionadded:: 7.1
+
+    The ``*_no_public``, ``*_reserved`` and ``*_public`` ranges were introduced
+    in Symfony 7.1.
diff --git a/reference/constraints/IsFalse.rst b/reference/constraints/IsFalse.rst
index 0b9ebe77491..3d0a1665944 100644
--- a/reference/constraints/IsFalse.rst
+++ b/reference/constraints/IsFalse.rst
@@ -93,9 +93,9 @@ method returns **false**:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addGetterConstraint('stateInvalid', new Assert\IsFalse([
-                    'message' => "You've entered an invalid state.",
-                ]));
+                $metadata->addGetterConstraint('stateInvalid', new Assert\IsFalse(
+                    message: "You've entered an invalid state.",
+                ));
             }
 
             public function isStateInvalid(): bool
diff --git a/reference/constraints/IsTrue.rst b/reference/constraints/IsTrue.rst
index 678371f6e69..b50ba4f3e8b 100644
--- a/reference/constraints/IsTrue.rst
+++ b/reference/constraints/IsTrue.rst
@@ -97,9 +97,9 @@ Then you can validate this method with ``IsTrue`` as follows:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addGetterConstraint('tokenValid', new IsTrue([
-                    'message' => 'The token is invalid.',
-                ]));
+                $metadata->addGetterConstraint('tokenValid', new IsTrue(
+                    message: 'The token is invalid.',
+                ));
             }
 
             public function isTokenValid(): bool
diff --git a/reference/constraints/Isbn.rst b/reference/constraints/Isbn.rst
index 954bff233d5..52d10565fe5 100644
--- a/reference/constraints/Isbn.rst
+++ b/reference/constraints/Isbn.rst
@@ -76,10 +76,10 @@ on an object that will contain an ISBN.
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('isbn', new Assert\Isbn([
-                    'type' => Assert\Isbn::ISBN_10,
-                    'message' => 'This value is not valid.',
-                ]));
+                $metadata->addPropertyConstraint('isbn', new Assert\Isbn(
+                    type: Assert\Isbn::ISBN_10,
+                    message: 'This value is not valid.',
+                ));
             }
         }
 
diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst
index 28e15976f3c..337b2dc6a1e 100644
--- a/reference/constraints/Json.rst
+++ b/reference/constraints/Json.rst
@@ -69,9 +69,9 @@ The ``Json`` constraint can be applied to a property or a "getter" method:
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('chapters', new Assert\Json([
-                    'message' => 'You\'ve entered an invalid Json.',
-                ]));
+                $metadata->addPropertyConstraint('chapters', new Assert\Json(
+                    message: 'You\'ve entered an invalid Json.',
+                ));
             }
         }
 
diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst
index 58c0df0d7a1..c1a8575070b 100644
--- a/reference/constraints/Length.rst
+++ b/reference/constraints/Length.rst
@@ -85,12 +85,12 @@ and ``50``, you might add the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('firstName', new Assert\Length([
-                    'min' => 2,
-                    'max' => 50,
-                    'minMessage' => 'Your first name must be at least {{ limit }} characters long',
-                    'maxMessage' => 'Your first name cannot be longer than {{ limit }} characters',
-                ]));
+                $metadata->addPropertyConstraint('firstName', new Assert\Length(
+                    min: 2,
+                    max: 50,
+                    minMessage: 'Your first name must be at least {{ limit }} characters long',
+                    maxMessage: 'Your first name cannot be longer than {{ limit }} characters',
+                ));
             }
         }
 
@@ -143,10 +143,6 @@ Can be one of the following constants of the
 * ``COUNT_GRAPHEMES``: Uses :phpfunction:`grapheme_strlen` counting the length of the string in
   graphemes, i.e. even emojis and ZWJ sequences of composed emojis count as 1 character.
 
-.. versionadded:: 6.3
-
-    The ``countUnit`` option was introduced in Symfony 6.3.
-
 ``exactly``
 ~~~~~~~~~~~
 
@@ -179,10 +175,6 @@ Parameter               Description
 ``{{ value_length }}``  The current value's length
 ======================  ============================================================
 
-.. versionadded:: 6.3
-
-    The `{{ value_length }}` parameter was introduced in Symfony 6.3.
-
 .. include:: /reference/constraints/_groups-option.rst.inc
 
 ``max``
@@ -213,10 +205,6 @@ Parameter               Description
 ``{{ value_length }}``  The current value's length
 ======================  ============================================================
 
-.. versionadded:: 6.3
-
-    The `{{ value_length }}` parameter was introduced in Symfony 6.3.
-
 ``min``
 ~~~~~~~
 
@@ -249,10 +237,6 @@ Parameter               Description
 ``{{ value_length }}``  The current value's length
 ======================  ============================================================
 
-.. versionadded:: 6.3
-
-    The `{{ value_length }}` parameter was introduced in Symfony 6.3.
-
 .. include:: /reference/constraints/_normalizer-option.rst.inc
 
 .. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/LessThan.rst b/reference/constraints/LessThan.rst
index 964bfbb3527..3d23bcda445 100644
--- a/reference/constraints/LessThan.rst
+++ b/reference/constraints/LessThan.rst
@@ -89,9 +89,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('siblings', new Assert\LessThan(5));
 
-                $metadata->addPropertyConstraint('age', new Assert\LessThan([
-                    'value' => 80,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\LessThan(
+                    value: 80,
+                ));
             }
         }
 
diff --git a/reference/constraints/LessThanOrEqual.rst b/reference/constraints/LessThanOrEqual.rst
index 9420c3e4376..ac66c62d7d0 100644
--- a/reference/constraints/LessThanOrEqual.rst
+++ b/reference/constraints/LessThanOrEqual.rst
@@ -88,9 +88,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('siblings', new Assert\LessThanOrEqual(5));
 
-                $metadata->addPropertyConstraint('age', new Assert\LessThanOrEqual([
-                    'value' => 80,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\LessThanOrEqual(
+                    value: 80,
+                ));
             }
         }
 
diff --git a/reference/constraints/Locale.rst b/reference/constraints/Locale.rst
index 49edd473d05..4bba45ae12b 100644
--- a/reference/constraints/Locale.rst
+++ b/reference/constraints/Locale.rst
@@ -78,9 +78,9 @@ Basic Usage
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('locale', new Assert\Locale([
-                    'canonicalize' => true,
-                ]));
+                $metadata->addPropertyConstraint('locale', new Assert\Locale(
+                    canonicalize: true,
+                ));
             }
         }
 
diff --git a/reference/constraints/Luhn.rst b/reference/constraints/Luhn.rst
index 8f5ef34c4ba..0c835204091 100644
--- a/reference/constraints/Luhn.rst
+++ b/reference/constraints/Luhn.rst
@@ -72,9 +72,9 @@ will contain a credit card number.
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('cardNumber', new Assert\Luhn([
-                    'message' => 'Please check your credit card number',
-                ]));
+                $metadata->addPropertyConstraint('cardNumber', new Assert\Luhn(
+                    message: 'Please check your credit card number',
+                ));
             }
         }
 
diff --git a/reference/constraints/MacAddress.rst b/reference/constraints/MacAddress.rst
new file mode 100644
index 00000000000..9a282ddf118
--- /dev/null
+++ b/reference/constraints/MacAddress.rst
@@ -0,0 +1,139 @@
+MacAddress
+==========
+
+.. versionadded:: 7.1
+
+    The ``MacAddress`` constraint was introduced in Symfony 7.1.
+
+This constraint ensures that the given value is a valid `MAC address`_ (internally it
+uses the ``FILTER_VALIDATE_MAC`` option of the :phpfunction:`filter_var` PHP
+function).
+
+==========  =====================================================================
+Applies to  :ref:`property or method <validation-property-target>`
+Class       :class:`Symfony\\Component\\Validator\\Constraints\\MacAddress`
+Validator   :class:`Symfony\\Component\\Validator\\Constraints\\MacAddressValidator`
+==========  =====================================================================
+
+Basic Usage
+-----------
+
+To use the MacAddress validator, apply it to a property on an object that
+can contain a MAC address:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/Device.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+
+        class Device
+        {
+            #[Assert\MacAddress]
+            protected string $mac;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\Device:
+            properties:
+                mac:
+                    - MacAddress: ~
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\Device">
+                <property name="max">
+                    <constraint name="MacAddress"/>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/Device.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class Device
+        {
+            // ...
+
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('mac', new Assert\MacAddress());
+            }
+        }
+
+.. include:: /reference/constraints/_empty-values-are-valid.rst.inc
+
+Options
+-------
+
+.. include:: /reference/constraints/_groups-option.rst.inc
+
+``message``
+~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This value is not a valid MAC address.``
+
+This is the message that will be shown if the value is not a valid MAC address.
+
+You can use the following parameters in this message:
+
+===============  ==============================================================
+Parameter            Description
+===============  ==============================================================
+``{{ value }}``  The current (invalid) value
+===============  ==============================================================
+
+.. include:: /reference/constraints/_normalizer-option.rst.inc
+
+.. include:: /reference/constraints/_payload-option.rst.inc
+
+.. _reference-constraint-mac-address-type:
+
+``type``
+~~~~~~~~
+
+**type**: ``string`` **default**: ``all``
+
+.. versionadded:: 7.1
+
+    The ``type`` option was introduced in Symfony 7.1.
+
+This option defines the kind of MAC addresses that are allowed. There are a lot
+of different possible values based on your needs:
+
+================================  =========================================
+Parameter                         Allowed MAC addresses
+================================  =========================================
+``all``                           All
+``all_no_broadcast``              All except broadcast
+``broadcast``                     Only broadcast
+``local_all``                     Only local
+``local_multicast_no_broadcast``  Only local and multicast except broadcast
+``local_multicast``               Only local and multicast
+``local_no_broadcast``            Only local except broadcast
+``local_unicast``                 Only local and unicast
+``multicast_all``                 Only multicast
+``multicast_no_broadcast``        Only multicast except broadcast
+``unicast_all``                   Only unicast
+``universal_all``                 Only universal
+``universal_unicast``             Only universal and unicast
+``universal_multicast``           Only universal and multicast
+================================  =========================================
+
+.. _`MAC address`: https://en.wikipedia.org/wiki/MAC_address
diff --git a/reference/constraints/NoSuspiciousCharacters.rst b/reference/constraints/NoSuspiciousCharacters.rst
index cfc23141553..00e28cd6da1 100644
--- a/reference/constraints/NoSuspiciousCharacters.rst
+++ b/reference/constraints/NoSuspiciousCharacters.rst
@@ -1,10 +1,6 @@
 NoSuspiciousCharacters
 ======================
 
-.. versionadded:: 6.3
-
-    The ``NoSuspiciousCharacters`` constraint was introduced in Symfony 6.3.
-
 Validates that the given string does not contain characters used in spoofing
 security attacks, such as invisible characters such as zero-width spaces or
 characters that are visually similar.
diff --git a/reference/constraints/NotEqualTo.rst b/reference/constraints/NotEqualTo.rst
index b8ee4cac32f..dd3f633b4a1 100644
--- a/reference/constraints/NotEqualTo.rst
+++ b/reference/constraints/NotEqualTo.rst
@@ -93,9 +93,9 @@ the following:
             {
                 $metadata->addPropertyConstraint('firstName', new Assert\NotEqualTo('Mary'));
 
-                $metadata->addPropertyConstraint('age', new Assert\NotEqualTo([
-                    'value' => 15,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\NotEqualTo(
+                    value: 15,
+                ));
             }
         }
 
diff --git a/reference/constraints/NotIdenticalTo.rst b/reference/constraints/NotIdenticalTo.rst
index 9ea93dc4b86..b2c20027292 100644
--- a/reference/constraints/NotIdenticalTo.rst
+++ b/reference/constraints/NotIdenticalTo.rst
@@ -94,9 +94,9 @@ The following constraints ensure that:
             {
                 $metadata->addPropertyConstraint('age', new Assert\NotIdenticalTo('Mary'));
 
-                $metadata->addPropertyConstraint('age', new Assert\NotIdenticalTo([
-                    'value' => 15,
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\NotIdenticalTo(
+                    value: 15,
+                ));
             }
         }
 
diff --git a/reference/constraints/PasswordStrength.rst b/reference/constraints/PasswordStrength.rst
index ddc3fd18043..0b242cacf08 100644
--- a/reference/constraints/PasswordStrength.rst
+++ b/reference/constraints/PasswordStrength.rst
@@ -1,10 +1,6 @@
 PasswordStrength
 ================
 
-.. versionadded:: 6.3
-
-    The ``PasswordStrength`` constraint was introduced in Symfony 6.3.
-
 Validates that the given password has reached the minimum strength required by
 the constraint. The strength of the password is not evaluated with a set of
 predefined rules (include a number, use lowercase and uppercase characters,
@@ -105,9 +101,9 @@ or by a custom password strength estimator.
 
     class User
     {
-        #[Assert\PasswordStrength([
-            'minScore' => PasswordStrength::STRENGTH_VERY_STRONG, // Very strong password required
-        ])]
+        #[Assert\PasswordStrength(
+            minScore: PasswordStrength::STRENGTH_VERY_STRONG, // Very strong password required
+        )]
         protected $rawPassword;
     }
 
@@ -127,8 +123,92 @@ The default message supplied when the password does not reach the minimum requir
 
     class User
     {
-        #[Assert\PasswordStrength([
-            'message' => 'Your password is too easy to guess. Company\'s security policy requires to use a stronger password.'
-        ])]
+        #[Assert\PasswordStrength(
+            message: 'Your password is too easy to guess. Company\'s security policy requires to use a stronger password.'
+        )]
         protected $rawPassword;
     }
+
+Customizing the Password Strength Estimation
+--------------------------------------------
+
+.. versionadded:: 7.2
+
+    The feature to customize the password strength estimation was introduced in Symfony 7.2.
+
+By default, this constraint calculates the strength of a password based on its
+length and the number of unique characters used. You can get the calculated
+password strength (e.g. to display it in the user interface) using the following
+static function::
+
+    use Symfony\Component\Validator\Constraints\PasswordStrengthValidator;
+
+    $passwordEstimatedStrength = PasswordStrengthValidator::estimateStrength($password);
+
+If you need to override the default password strength estimation algorithm, you
+can pass a ``Closure`` to the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator`
+constructor (e.g. using the :doc:`service closures </service_container/service_closures>`).
+
+First, create a custom password strength estimation algorithm within a dedicated
+callable class::
+
+    namespace App\Validator;
+
+    class CustomPasswordStrengthEstimator
+    {
+        /**
+         * @return PasswordStrength::STRENGTH_*
+         */
+        public function __invoke(string $password): int
+        {
+            // Your custom password strength estimation algorithm
+        }
+    }
+
+Then, configure the :class:`Symfony\\Component\\Validator\\Constraints\\PasswordStrengthValidator`
+service to use your own estimator:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/services.yaml
+        services:
+            custom_password_strength_estimator:
+                class: App\Validator\CustomPasswordStrengthEstimator
+
+            Symfony\Component\Validator\Constraints\PasswordStrengthValidator:
+                arguments: [!closure '@custom_password_strength_estimator']
+
+    .. code-block:: xml
+
+        <!-- config/services.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
+
+            <services>
+                <service id="custom_password_strength_estimator" class="App\Validator\CustomPasswordStrengthEstimator"/>
+
+                <service id="Symfony\Component\Validator\Constraints\PasswordStrengthValidator">
+                    <argument type="closure" id="custom_password_strength_estimator"/>
+                </service>
+            </services>
+        </container>
+
+    .. code-block:: php
+
+        // config/services.php
+        namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+        use Symfony\Component\Validator\Constraints\PasswordStrengthValidator;
+
+        return function (ContainerConfigurator $container): void {
+            $services = $container->services();
+
+            $services->set('custom_password_strength_estimator', CustomPasswordStrengthEstimator::class);
+
+            $services->set(PasswordStrengthValidator::class)
+                ->args([closure('custom_password_strength_estimator')]);
+        };
diff --git a/reference/constraints/Range.rst b/reference/constraints/Range.rst
index edd199c48b9..46a9e3799b3 100644
--- a/reference/constraints/Range.rst
+++ b/reference/constraints/Range.rst
@@ -78,11 +78,11 @@ you might add the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('height', new Assert\Range([
-                    'min' => 120,
-                    'max' => 180,
-                    'notInRangeMessage' => 'You must be between {{ min }}cm and {{ max }}cm tall to enter',
-                ]));
+                $metadata->addPropertyConstraint('height', new Assert\Range(
+                    min: 120,
+                    max: 180,
+                    notInRangeMessage: 'You must be between {{ min }}cm and {{ max }}cm tall to enter',
+                ));
             }
         }
 
@@ -154,10 +154,10 @@ date must lie within the current year like this:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('startDate', new Assert\Range([
-                    'min' => 'first day of January',
-                    'max' => 'first day of January next year',
-                ]));
+                $metadata->addPropertyConstraint('startDate', new Assert\Range(
+                    min: 'first day of January',
+                    max: 'first day of January next year',
+                ));
             }
         }
 
@@ -224,10 +224,10 @@ dates. If you want to fix the timezone, append it to the date string:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('startDate', new Assert\Range([
-                    'min' => 'first day of January UTC',
-                    'max' => 'first day of January next year UTC',
-                ]));
+                $metadata->addPropertyConstraint('startDate', new Assert\Range(
+                    min: 'first day of January UTC',
+                    max: 'first day of January next year UTC',
+                ));
             }
         }
 
@@ -294,10 +294,10 @@ can check that a delivery date starts within the next five hours like this:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('deliveryDate', new Assert\Range([
-                    'min' => 'now',
-                    'max' => '+5 hours',
-                ]));
+                $metadata->addPropertyConstraint('deliveryDate', new Assert\Range(
+                    min: 'now',
+                    max: '+5 hours',
+                ));
             }
         }
 
diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst
index d17b339b475..e3b4d4711b2 100644
--- a/reference/constraints/Regex.rst
+++ b/reference/constraints/Regex.rst
@@ -71,9 +71,9 @@ more word characters at the beginning of your string:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('description', new Assert\Regex([
-                    'pattern' => '/^\w+/',
-                ]));
+                $metadata->addPropertyConstraint('description', new Assert\Regex(
+                    pattern: '/^\w+/',
+                ));
             }
         }
 
@@ -145,11 +145,11 @@ it a custom message:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('firstName', new Assert\Regex([
-                    'pattern' => '/\d/',
-                    'match' => false,
-                    'message' => 'Your name cannot contain a number',
-                ]));
+                $metadata->addPropertyConstraint('firstName', new Assert\Regex(
+                    pattern: '/\d/',
+                    match: false,
+                    message: 'Your name cannot contain a number',
+                ));
             }
         }
 
@@ -236,10 +236,10 @@ need to specify the HTML5 compatible pattern in the ``htmlPattern`` option:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('name', new Assert\Regex([
-                    'pattern' => '/^[a-z]+$/i',
-                    'htmlPattern' => '[a-zA-Z]+',
-                ]));
+                $metadata->addPropertyConstraint('name', new Assert\Regex(
+                    pattern: '/^[a-z]+$/i',
+                    htmlPattern: '[a-zA-Z]+',
+                ));
             }
         }
 
@@ -272,14 +272,10 @@ Parameter          Description
 ``{{ pattern }}``  The expected matching pattern
 =================  ==============================================================
 
-.. versionadded:: 6.3
-
-   The ``{{ pattern }}`` parameter was introduced in 6.3.
-
 ``pattern``
 ~~~~~~~~~~~
 
-**type**: ``string`` [:ref:`default option <validation-default-option>`]
+**type**: ``string``
 
 This required option is the regular expression pattern that the input will
 be matched against. By default, this validator will fail if the input string
diff --git a/reference/constraints/Sequentially.rst b/reference/constraints/Sequentially.rst
index 7620997f0a3..078be338cdf 100644
--- a/reference/constraints/Sequentially.rst
+++ b/reference/constraints/Sequentially.rst
@@ -110,7 +110,7 @@ You can validate each of these constraints sequentially to solve these issues:
                 $metadata->addPropertyConstraint('address', new Assert\Sequentially([
                     new Assert\NotNull(),
                     new Assert\Type('string'),
-                    new Assert\Length(['min' => 10]),
+                    new Assert\Length(min: 10),
                     new Assert\Regex(self::ADDRESS_REGEX),
                     new AcmeAssert\Geolocalizable(),
                 ]));
@@ -123,7 +123,7 @@ Options
 ``constraints``
 ~~~~~~~~~~~~~~~
 
-**type**: ``array`` [:ref:`default option <validation-default-option>`]
+**type**: ``array``
 
 This required option is the array of validation constraints that you want
 to apply sequentially.
diff --git a/reference/constraints/Time.rst b/reference/constraints/Time.rst
index 1732fb584f0..6d4de73398f 100644
--- a/reference/constraints/Time.rst
+++ b/reference/constraints/Time.rst
@@ -115,8 +115,4 @@ Option     Pattern                          Correct value   Incorrect value
 ``false``  ``/^(\d{2}):(\d{2})$/``          ``12:00``       ``12:00:00``
 =========  ===============================  ==============  ================
 
-.. versionadded:: 6.4
-
-    The ``withSeconds`` option was introduced in Symfony 6.4.
-
 .. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/Twig.rst b/reference/constraints/Twig.rst
new file mode 100644
index 00000000000..e38b4507d7a
--- /dev/null
+++ b/reference/constraints/Twig.rst
@@ -0,0 +1,130 @@
+Twig Constraint
+===============
+
+.. versionadded:: 7.3
+
+    The ``Twig`` constraint was introduced in Symfony 7.3.
+
+Validates that a given string contains valid :ref:`Twig syntax <twig-language>`.
+This is particularly useful when template content is user-generated or
+configurable, and you want to ensure it can be rendered by the Twig engine.
+
+.. note::
+
+    Using this constraint requires having the ``symfony/twig-bridge`` package
+    installed in your application (e.g. by running ``composer require symfony/twig-bridge``).
+
+==========  ===================================================================
+Applies to  :ref:`property or method <validation-property-target>`
+Class       :class:`Symfony\\Bridge\\Twig\\Validator\\Constraints\\Twig`
+Validator   :class:`Symfony\\Bridge\\Twig\\Validator\\Constraints\\TwigValidator`
+==========  ===================================================================
+
+Basic Usage
+-----------
+
+Apply the ``Twig`` constraint to validate the contents of any property or the
+returned value of any method::
+
+    use Symfony\Bridge\Twig\Validator\Constraints\Twig;
+
+    class Template
+    {
+        #[Twig]
+        private string $templateCode;
+    }
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/Page.php
+        namespace App\Entity;
+
+        use Symfony\Bridge\Twig\Validator\Constraints\Twig;
+
+        class Page
+        {
+            #[Twig]
+            private string $templateCode;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\Page:
+            properties:
+                templateCode:
+                    - Symfony\Bridge\Twig\Validator\Constraints\Twig: ~
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\Page">
+                <property name="templateCode">
+                    <constraint name="Symfony\Bridge\Twig\Validator\Constraints\Twig"/>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/Page.php
+        namespace App\Entity;
+
+        use Symfony\Bridge\Twig\Validator\Constraints\Twig;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class Page
+        {
+            // ...
+
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('templateCode', new Twig());
+            }
+        }
+
+Constraint Options
+------------------
+
+``message``
+~~~~~~~~~~~
+
+**type**: ``message`` **default**: ``This value is not a valid Twig template.``
+
+This is the message displayed when the given string does *not* contain valid Twig syntax::
+
+    // ...
+
+    class Page
+    {
+        #[Twig(message: 'Check this Twig code; it contains errors.')]
+        private string $templateCode;
+    }
+
+This message has no parameters.
+
+``skipDeprecations``
+~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``true``
+
+If ``true``, Twig deprecation warnings are ignored during validation. Set it to
+``false`` to trigger validation errors when the given Twig code contains any deprecations::
+
+    // ...
+
+    class Page
+    {
+        #[Twig(skipDeprecations: false)]
+        private string $templateCode;
+    }
+
+This can be helpful when enforcing stricter template rules or preparing for major
+Twig version upgrades.
diff --git a/reference/constraints/Type.rst b/reference/constraints/Type.rst
index b0a3dad4552..b49536dff8b 100644
--- a/reference/constraints/Type.rst
+++ b/reference/constraints/Type.rst
@@ -127,14 +127,14 @@ The following example checks if ``emailAddress`` is an instance of ``Symfony\Com
 
                 $metadata->addPropertyConstraint('firstName', new Assert\Type('string'));
 
-                $metadata->addPropertyConstraint('age', new Assert\Type([
-                    'type' => 'integer',
-                    'message' => 'The value {{ value }} is not a valid {{ type }}.',
-                ]));
-
-                $metadata->addPropertyConstraint('accessCode', new Assert\Type([
-                    'type' => ['alpha', 'digit'],
-                ]));
+                $metadata->addPropertyConstraint('age', new Assert\Type(
+                    type: 'integer',
+                    message: 'The value {{ value }} is not a valid {{ type }}.',
+                ));
+
+                $metadata->addPropertyConstraint('accessCode', new Assert\Type(
+                    type: ['alpha', 'digit'],
+                ));
             }
         }
 
@@ -169,7 +169,7 @@ Parameter        Description
 ``type``
 ~~~~~~~~
 
-**type**: ``string`` or ``array`` [:ref:`default option <validation-default-option>`]
+**type**: ``string`` or ``array``
 
 This required option defines the type or collection of types allowed for the
 given value. Each type is either the FQCN (fully qualified class name) of some
@@ -194,6 +194,11 @@ PHP class/interface or a valid PHP datatype (checked by PHP's ``is_()`` function
 * :phpfunction:`resource <is_resource>`
 * :phpfunction:`null <is_null>`
 
+If you're dealing with arrays, you can use the following types in the constraint:
+
+* ``list`` which uses :phpfunction:`array_is_list <array_is_list>` internally
+* ``associative_array`` which is true for any **non-empty** array that is not a list
+
 Also, you can use ``ctype_*()`` functions from corresponding
 `built-in PHP extension`_. Consider `a list of ctype functions`_:
 
@@ -212,15 +217,16 @@ Also, you can use ``ctype_*()`` functions from corresponding
 Make sure that the proper :phpfunction:`locale <setlocale>` is set before
 using one of these.
 
+.. versionadded:: 7.1
+
+    The ``list`` and ``associative_array`` types were introduced in Symfony
+    7.1.
+
 Finally, you can use aggregated functions:
 
 * ``number``: ``is_int || is_float && !is_nan``
 * ``finite-float``: ``is_float && is_finite``
 * ``finite-number``: ``is_int || is_float && is_finite``
 
-.. versionadded:: 6.4
-
-    ``number``, ``finite-float`` and ``finite-number`` were introduced in Symfony 6.4.
-
 .. _built-in PHP extension: https://www.php.net/book.ctype
 .. _a list of ctype functions: https://www.php.net/ref.ctype
diff --git a/reference/constraints/Ulid.rst b/reference/constraints/Ulid.rst
index ed7dfe7ed96..4094bab98f5 100644
--- a/reference/constraints/Ulid.rst
+++ b/reference/constraints/Ulid.rst
@@ -73,6 +73,21 @@ Basic Usage
 Options
 -------
 
+``format``
+~~~~~~~~~~
+
+**type**: ``string`` **default**: ``Ulid::FORMAT_BASE_32``
+
+The format of the ULID to validate. The following formats are available:
+
+* ``Ulid::FORMAT_BASE_32``: The ULID is encoded in `base32`_ (default)
+* ``Ulid::FORMAT_BASE_58``: The ULID is encoded in `base58`_
+* ``Ulid::FORMAT_RFC4122``: The ULID is encoded in the `RFC 4122 format`_
+
+.. versionadded:: 7.2
+
+    The ``format`` option was introduced in Symfony 7.2.
+
 .. include:: /reference/constraints/_groups-option.rst.inc
 
 ``message``
@@ -96,3 +111,6 @@ Parameter        Description
 .. include:: /reference/constraints/_payload-option.rst.inc
 
 .. _`Universally Unique Lexicographically Sortable Identifier (ULID)`: https://github.com/ulid/spec
+.. _`base32`: https://en.wikipedia.org/wiki/Base32
+.. _`base58`: https://en.wikipedia.org/wiki/Binary-to-text_encoding#Base58
+.. _`RFC 4122 format`: https://datatracker.ietf.org/doc/html/rfc4122
diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst
index 6d8a9fc0f31..9ce84139cd5 100644
--- a/reference/constraints/Unique.rst
+++ b/reference/constraints/Unique.rst
@@ -95,10 +95,6 @@ Options
 
 **type**: ``array`` | ``string``
 
-.. versionadded:: 6.1
-
-    The ``fields`` option was introduced in Symfony 6.1.
-
 This is defines the key or keys in a collection that should be checked for
 uniqueness. By default, all collection keys are checked for uniqueness.
 
@@ -166,14 +162,30 @@ collection::
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('coordinates', new Assert\Unique([
-                    'fields' => ['latitude', 'longitude'],
-                ]));
+                $metadata->addPropertyConstraint('coordinates', new Assert\Unique(
+                    fields: ['latitude', 'longitude'],
+                ));
             }
         }
 
 .. include:: /reference/constraints/_groups-option.rst.inc
 
+``errorPath``
+~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``null``
+
+.. versionadded:: 7.2
+
+    The ``errorPath`` option was introduced in Symfony 7.2.
+
+If a validation error occurs, the error message is, by default, bound to the
+first element in the collection. Use this option to bind the error message to a
+specific field within the first item of the collection.
+
+The value of this option must use any :doc:`valid PropertyAccess syntax </components/property_access>`
+(e.g. ``'point_of_interest'``, ``'user.email'``).
+
 ``message``
 ~~~~~~~~~~~
 
@@ -204,4 +216,17 @@ trailing whitespace during validation.
 
 .. include:: /reference/constraints/_payload-option.rst.inc
 
+``stopOnFirstError``
+~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``true``
+
+By default, this constraint stops at the first violation. If this option is set
+to ``false``, validation continues on all elements and returns all detected
+:class:`Symfony\\Component\\Validator\\ConstraintViolation` objects.
+
+.. versionadded:: 7.3
+
+    The ``stopOnFirstError`` option was introduced in Symfony 7.3.
+
 .. _`PHP callable`: https://www.php.net/callable
diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst
index 0e1731371a5..0ab2c0a8cbd 100644
--- a/reference/constraints/UniqueEntity.rst
+++ b/reference/constraints/UniqueEntity.rst
@@ -95,9 +95,9 @@ between all of the rows in your user table:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addConstraint(new UniqueEntity([
-                    'fields' => 'email',
-                ]));
+                $metadata->addConstraint(new UniqueEntity(
+                    fields: 'email',
+                ));
 
                 $metadata->addPropertyConstraint('email', new Assert\Email());
             }
@@ -260,7 +260,7 @@ Now, the message would be bound to the ``port`` field with this configuration.
 ``fields``
 ~~~~~~~~~~
 
-**type**: ``array`` | ``string`` [:ref:`default option <validation-default-option>`]
+**type**: ``array`` | ``string``
 
 This required option is the field (or list of fields) on which this entity
 should be unique. For example, if you specified both the ``email`` and ``name``
@@ -346,10 +346,10 @@ this option to specify one or more fields to only ignore ``null`` values on them
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata)
             {
-                $metadata->addConstraint(new UniqueEntity([
-                    'fields' => ['email', 'phoneNumber'],
-                    'ignoreNull' => 'phoneNumber',
-                ]));
+                $metadata->addConstraint(new UniqueEntity(
+                    fields: ['email', 'phoneNumber'],
+                    ignoreNull: 'phoneNumber',
+                ));
 
                 // ...
             }
@@ -361,11 +361,6 @@ this option to specify one or more fields to only ignore ``null`` values on them
     database, you might see insertion errors when your application attempts to
     persist entities that the ``UniqueEntity`` constraint considers valid.
 
-.. versionadded:: 6.3
-
-    The option to ignore ``null`` values for specific fields was introduced
-    in Symfony 6.3.
-
 ``message``
 ~~~~~~~~~~~
 
diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst
index 2c3420df7c6..c3fac520f96 100644
--- a/reference/constraints/Url.rst
+++ b/reference/constraints/Url.rst
@@ -152,9 +152,9 @@ Parameter        Description
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('bioUrl', new Assert\Url([
-                    'message' => 'The url "{{ value }}" is not a valid url.',
-                ]));
+                $metadata->addPropertyConstraint('bioUrl', new Assert\Url(
+                    message: 'The url "{{ value }}" is not a valid url.',
+                ));
             }
         }
 
@@ -231,9 +231,9 @@ the ``ftp://`` type URLs to be valid, redefine the ``protocols`` array, listing
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('bioUrl', new Assert\Url([
-                    'protocols' => ['http', 'https', 'ftp'],
-                ]));
+                $metadata->addPropertyConstraint('bioUrl', new Assert\Url(
+                    protocols: ['http', 'https', 'ftp'],
+                ));
             }
         }
 
@@ -302,8 +302,124 @@ also relative URLs that contain no protocol (e.g. ``//example.com``).
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('bioUrl', new Assert\Url([
-                    'relativeProtocol' => true,
-                ]));
+                $metadata->addPropertyConstraint('bioUrl', new Assert\Url(
+                    relativeProtocol: true,
+                ));
             }
         }
+
+``requireTld``
+~~~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``false``
+
+.. versionadded:: 7.1
+
+    The ``requireTld`` option was introduced in Symfony 7.1.
+
+.. deprecated:: 7.1
+
+    Not setting the ``requireTld`` option is deprecated since Symfony 7.1
+    and will default to ``true`` in Symfony 8.0.
+
+By default, URLs like ``https://aaa`` or ``https://foobar`` are considered valid
+because they are technically correct according to the `URL spec`_. If you set this option
+to ``true``, the host part of the URL will have to include a TLD (top-level domain
+name): e.g. ``https://example.com`` will be valid but ``https://example`` won't.
+
+.. note::
+
+    This constraint does not validate that the given TLD value is included in
+    the `list of official top-level domains`_ (because that list is growing
+    continuously and it's hard to keep track of it).
+
+``tldMessage``
+~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This URL does not contain a TLD.``
+
+.. versionadded:: 7.1
+
+    The ``tldMessage`` option was introduced in Symfony 7.1.
+
+This message is shown if the ``requireTld`` option is set to ``true`` and the URL
+does not contain at least one TLD.
+
+You can use the following parameters in this message:
+
+===============  ==============================================================
+Parameter        Description
+===============  ==============================================================
+``{{ value }}``  The current (invalid) value
+``{{ label }}``  Corresponding form field label
+===============  ==============================================================
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/Website.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+
+        class Website
+        {
+            #[Assert\Url(
+                requireTld: true,
+                tldMessage: 'Add at least one TLD to the {{ value }} URL.',
+            )]
+            protected string $homepageUrl;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\Website:
+            properties:
+                homepageUrl:
+                    - Url:
+                        requireTld: true
+                        tldMessage: Add at least one TLD to the {{ value }} URL.
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\Website">
+                <property name="homepageUrl">
+                    <constraint name="Url">
+                        <option name="requireTld">true</option>
+                        <option name="tldMessage">Add at least one TLD to the {{ value }} URL.</option>
+                    </constraint>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/Website.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class Website
+        {
+            // ...
+
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('homepageUrl', new Assert\Url(
+                    requireTld: true,
+                    tldMessage: 'Add at least one TLD to the {{ value }} URL.',
+                ));
+            }
+        }
+
+.. _`URL spec`: https://datatracker.ietf.org/doc/html/rfc1738
+.. _`list of official top-level domains`: https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst
index d8ff5fadb8b..c9f6c9741bf 100644
--- a/reference/constraints/Uuid.rst
+++ b/reference/constraints/Uuid.rst
@@ -129,15 +129,6 @@ you can also use the following PHP constants to refer to each UUID version:
 * ``Uuid::V7_MONOTONIC``
 * ``Uuid::V8_CUSTOM``
 
-.. versionadded:: 6.2
-
-    UUID versions 7 and 8 were introduced in Symfony 6.2.
-
-.. versionadded:: 6.4
-
-    Using a single integer instead of an integer array for this option
-    was introduced in Symfony 6.4.
-
 .. _`Universally unique identifier (UUID)`: https://en.wikipedia.org/wiki/Universally_unique_identifier
 .. _`RFC 4122`: https://tools.ietf.org/html/rfc4122
 .. _`UUID versions`: https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions
diff --git a/reference/constraints/Valid.rst b/reference/constraints/Valid.rst
index 1f99b666419..61a2c1d992c 100644
--- a/reference/constraints/Valid.rst
+++ b/reference/constraints/Valid.rst
@@ -149,7 +149,7 @@ stores an ``Address`` instance in the ``$address`` property::
             {
                 $metadata->addPropertyConstraint('street', new Assert\NotBlank());
                 $metadata->addPropertyConstraint('zipCode', new Assert\NotBlank());
-                $metadata->addPropertyConstraint('zipCode', new Assert\Length(['max' => 5]));
+                $metadata->addPropertyConstraint('zipCode', new Assert\Length(max: 5));
             }
         }
 
@@ -166,7 +166,7 @@ stores an ``Address`` instance in the ``$address`` property::
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
                 $metadata->addPropertyConstraint('firstName', new Assert\NotBlank());
-                $metadata->addPropertyConstraint('firstName', new Assert\Length(['min' => 4]));
+                $metadata->addPropertyConstraint('firstName', new Assert\Length(min: 4));
                 $metadata->addPropertyConstraint('lastName', new Assert\NotBlank());
             }
         }
diff --git a/reference/constraints/Week.rst b/reference/constraints/Week.rst
new file mode 100644
index 00000000000..b3c1b0ca122
--- /dev/null
+++ b/reference/constraints/Week.rst
@@ -0,0 +1,172 @@
+Week
+====
+
+.. versionadded:: 7.2
+
+    The ``Week`` constraint was introduced in Symfony 7.2.
+
+Validates that a given string (or an object implementing the ``Stringable`` PHP
+interface) represents a valid week number according to the `ISO-8601`_ standard
+(e.g. ``2025-W01``).
+
+==========  =======================================================================
+Applies to  :ref:`property or method <validation-property-target>`
+Class       :class:`Symfony\\Component\\Validator\\Constraints\\Week`
+Validator   :class:`Symfony\\Component\\Validator\\Constraints\\WeekValidator`
+==========  =======================================================================
+
+Basic Usage
+-----------
+
+If you wanted to ensure that the ``startWeek`` property of an ``OnlineCourse``
+class is between the first and the twentieth week of the year 2022, you could do
+the following:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/OnlineCourse.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+
+        class OnlineCourse
+        {
+            #[Assert\Week(min: '2022-W01', max: '2022-W20')]
+            protected string $startWeek;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\OnlineCourse:
+            properties:
+                startWeek:
+                    - Week:
+                        min: '2022-W01'
+                        max: '2022-W20'
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\OnlineCourse">
+                <property name="startWeek">
+                    <constraint name="Week">
+                        <option name="min">2022-W01</option>
+                        <option name="max">2022-W20</option>
+                    </constraint>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/OnlineCourse.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class OnlineCourse
+        {
+            // ...
+
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('startWeek', new Assert\Week(
+                    min: '2022-W01',
+                    max: '2022-W20',
+                ));
+            }
+        }
+
+This constraint not only checks that the value matches the week number pattern,
+but it also verifies that the specified week actually exists in the calendar.
+According to the ISO-8601 standard, years can have either 52 or 53 weeks. For example,
+``2022-W53`` is not valid because 2022 only had 52 weeks; but ``2020-W53`` is
+valid because 2020 had 53 weeks.
+
+Options
+-------
+
+``min``
+~~~~~~~
+
+**type**: ``string`` **default**: ``null``
+
+The minimum week number that the value must match.
+
+``max``
+~~~~~~~
+
+**type**: ``string`` **default**: ``null``
+
+The maximum week number that the value must match.
+
+.. include:: /reference/constraints/_groups-option.rst.inc
+
+``invalidFormatMessage``
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This value does not represent a valid week in the ISO 8601 format.``
+
+This is the message that will be shown if the value does not match the ISO 8601
+week format.
+
+``invalidWeekNumberMessage``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``The week "{{ value }}" is not a valid week.``
+
+This is the message that will be shown if the value does not match a valid week
+number.
+
+You can use the following parameters in this message:
+
+================  ==================================================
+Parameter         Description
+================  ==================================================
+``{{ value }}``   The value that was passed to the constraint
+================  ==================================================
+
+``tooLowMessage``
+~~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``The value should not be before week "{{ min }}".``
+
+This is the message that will be shown if the value is lower than the minimum
+week number.
+
+You can use the following parameters in this message:
+
+================  ==================================================
+Parameter         Description
+================  ==================================================
+``{{ min }}``     The minimum week number
+================  ==================================================
+
+``tooHighMessage``
+~~~~~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``The value should not be after week "{{ max }}".``
+
+This is the message that will be shown if the value is higher than the maximum
+week number.
+
+You can use the following parameters in this message:
+
+================  ==================================================
+Parameter         Description
+================  ==================================================
+``{{ max }}``     The maximum week number
+================  ==================================================
+
+.. include:: /reference/constraints/_payload-option.rst.inc
+
+.. _`ISO-8601`: https://en.wikipedia.org/wiki/ISO_8601
diff --git a/reference/constraints/When.rst b/reference/constraints/When.rst
index ca45293898c..4b2e8eb7590 100644
--- a/reference/constraints/When.rst
+++ b/reference/constraints/When.rst
@@ -1,10 +1,6 @@
 When
 ====
 
-.. versionadded:: 6.2
-
-    The ``When`` constraint was introduced in Symfony 6.2.
-
 This constraint allows you to apply constraints validation only if the
 provided expression returns true. See `Basic Usage`_ for an example.
 
@@ -13,6 +9,7 @@ Applies to  :ref:`class <validation-class-target>`
             or :ref:`property/method <validation-property-target>`
 Options     - `expression`_
             - `constraints`_
+            _ `otherwise`_
             - `groups`_
             - `payload`_
             - `values`_
@@ -51,7 +48,7 @@ properties::
 To validate the object, you have some requirements:
 
 A) If ``type`` is ``percent``, then ``value`` must be less than or equal 100;
-B) If ``type`` is ``absolute``, then ``value`` can be anything;
+B) If ``type`` is not ``percent``, then ``value`` must be less than 9999;
 C) No matter the value of ``type``, the ``value`` must be greater than 0.
 
 One way to accomplish this is with the When constraint:
@@ -73,6 +70,9 @@ One way to accomplish this is with the When constraint:
                 constraints: [
                     new Assert\LessThanOrEqual(100, message: 'The value should be between 1 and 100!')
                 ],
+                otherwise: [
+                    new Assert\LessThan(9999, message: 'The value should be less than 9999!')
+                ],
             )]
             private ?int $value;
 
@@ -92,6 +92,10 @@ One way to accomplish this is with the When constraint:
                             - LessThanOrEqual:
                                 value: 100
                                 message: "The value should be between 1 and 100!"
+                        otherwise:
+                            - LessThan:
+                                value: 9999
+                                message: "The value should be less than 9999!"
 
     .. code-block:: xml
 
@@ -113,6 +117,12 @@ One way to accomplish this is with the When constraint:
                                 <option name="message">The value should be between 1 and 100!</option>
                             </constraint>
                         </option>
+                        <option name="otherwise">
+                            <constraint name="LessThan">
+                                <option name="value">9999</option>
+                                <option name="message">The value should be less than 9999!</option>
+                            </constraint>
+                        </option>
                     </constraint>
                 </property>
             </class>
@@ -131,15 +141,21 @@ One way to accomplish this is with the When constraint:
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
                 $metadata->addPropertyConstraint('value', new Assert\GreaterThan(0));
-                $metadata->addPropertyConstraint('value', new Assert\When([
-                    'expression' => 'this.getType() == "percent"',
-                    'constraints' => [
-                        new Assert\LessThanOrEqual([
-                            'value' => 100,
-                            'message' => 'The value should be between 1 and 100!',
-                        ]),
+                $metadata->addPropertyConstraint('value', new Assert\When(
+                    expression: 'this.getType() == "percent"',
+                    constraints: [
+                        new Assert\LessThanOrEqual(
+                            value: 100,
+                            message: 'The value should be between 1 and 100!',
+                        ),
                     ],
-                ]));
+                    otherwise: [
+                        new Assert\LessThan(
+                            value: 9999,
+                            message: 'The value should be less than 9999!',
+                        ),
+                    ],
+                ));
             }
 
             // ...
@@ -158,17 +174,15 @@ Options
 ``expression``
 ~~~~~~~~~~~~~~
 
-**type**: ``string``
-
-The condition written with the expression language syntax that will be evaluated.
-If the expression evaluates to a falsey value (i.e. using ``==``, not ``===``),
-validation of constraints won't be triggered.
+**type**: ``string|Closure``
 
-To learn more about the expression language syntax, see
-:doc:`/reference/formats/expression_language`.
+The condition evaluated to decide if the constraint is applied or not. It can be
+defined as a closure or a string using the :doc:`expression language syntax </reference/formats/expression_language>`.
+If the result is a falsey value (``false``, ``null``, ``0``, an empty string or
+an empty array) the constraints defined in the ``constraints`` option won't be
+applied but the constraints defined in ``otherwise`` option (if provided) will be applied.
 
-Depending on how you use the constraint, you have access to 1 or 2 variables
-in your expression:
+**When using an expression**, you access to the following variables:
 
 ``this``
     The object being validated (e.g. an instance of Discount).
@@ -176,9 +190,21 @@ in your expression:
     Either the object being validated (when the constraint is applied to a class),
     the value of the property being validated (when applied to a property),
     or the :doc:`raw value </validation/raw_values>`.
+``context``
+    The :class:`Symfony\\Component\\Validator\\Context\\ExecutionContextInterface`
+    object that provides information such as the currently validated class, the
+    name of the currently validated property, the list of violations, etc.
+
+.. versionadded:: 7.2
+
+    The ``context`` variable in expressions was introduced in Symfony 7.2.
+
+**When using a closure**, the first argument is the object being validated.
 
-The ``value`` variable can be used when you want to execute more complex
-validation based on its value:
+.. versionadded:: 7.3
+
+    The support for closures in the ``expression`` option was introduced in Symfony 7.3
+    and requires PHP 8.5.
 
 .. configuration-block::
 
@@ -192,11 +218,21 @@ validation based on its value:
 
         class Discount
         {
+            // either using an expression...
             #[Assert\When(
                 expression: 'value == "percent"',
                 constraints: [new Assert\Callback('doComplexValidation')],
             )]
+
+            // ... or using a closure
+            #[Assert\When(
+                expression: static function (Discount $discount) {
+                    return $discount->getType() === 'percent';
+                },
+                constraints: [new Assert\Callback('doComplexValidation')],
+            )]
             private ?string $type;
+
             // ...
 
             public function doComplexValidation(ExecutionContextInterface $context, $payload): void
@@ -253,12 +289,12 @@ validation based on its value:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('type', new Assert\When([
-                    'expression' => 'value == "percent"',
-                    'constraints' => [
+                $metadata->addPropertyConstraint('type', new Assert\When(
+                    expression: 'value == "percent"',
+                    constraints: [
                         new Assert\Callback('doComplexValidation'),
                     ],
-                ]));
+                ));
             }
 
             public function doComplexValidation(ExecutionContextInterface $context, $payload): void
@@ -276,9 +312,16 @@ You can also pass custom variables using the `values`_ option.
 
 One or multiple constraints that are applied if the expression returns true.
 
-.. versionadded:: 6.4
+``otherwise``
+~~~~~~~~~~~~~
+
+**type**: ``array|Constraint``
+
+One or multiple constraints that are applied if the expression returns false.
+
+.. versionadded:: 7.3
 
-    Passing a single ``Constraint`` instead of an array was introduced in Symfony 6.4.
+    The ``otherwise`` option was introduced in Symfony 7.3.
 
 .. include:: /reference/constraints/_groups-option.rst.inc
 
diff --git a/reference/constraints/WordCount.rst b/reference/constraints/WordCount.rst
new file mode 100644
index 00000000000..392f8a5bcb7
--- /dev/null
+++ b/reference/constraints/WordCount.rst
@@ -0,0 +1,150 @@
+WordCount
+=========
+
+.. versionadded:: 7.2
+
+    The ``WordCount`` constraint was introduced in Symfony 7.2.
+
+Validates that a string (or an object implementing the ``Stringable`` PHP interface)
+contains a given number of words. Internally, this constraint uses the
+:phpclass:`IntlBreakIterator` class to count the words depending on your locale.
+
+==========  =======================================================================
+Applies to  :ref:`property or method <validation-property-target>`
+Class       :class:`Symfony\\Component\\Validator\\Constraints\\WordCount`
+Validator   :class:`Symfony\\Component\\Validator\\Constraints\\WordCountValidator`
+==========  =======================================================================
+
+Basic Usage
+-----------
+
+If you wanted to ensure that the ``content`` property of a ``BlogPostDTO``
+class contains between 100 and 200 words, you could do the following:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/BlogPostDTO.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+
+        class BlogPostDTO
+        {
+            #[Assert\WordCount(min: 100, max: 200)]
+            protected string $content;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\BlogPostDTO:
+            properties:
+                content:
+                    - WordCount:
+                        min: 100
+                        max: 200
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\BlogPostDTO">
+                <property name="content">
+                    <constraint name="WordCount">
+                        <option name="min">100</option>
+                        <option name="max">200</option>
+                    </constraint>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/BlogPostDTO.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class BlogPostDTO
+        {
+            // ...
+
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('content', new Assert\WordCount(
+                    min: 100,
+                    max: 200,
+                ));
+            }
+        }
+
+Options
+-------
+
+``min``
+~~~~~~~
+
+**type**: ``integer`` **default**: ``null``
+
+The minimum number of words that the value must contain.
+
+``max``
+~~~~~~~
+
+**type**: ``integer`` **default**: ``null``
+
+The maximum number of words that the value must contain.
+
+``locale``
+~~~~~~~~~~
+
+**type**: ``string`` **default**: ``null``
+
+The locale to use for counting the words by using the :phpclass:`IntlBreakIterator`
+class. The default value (``null``) means that the constraint uses the current
+user locale.
+
+.. include:: /reference/constraints/_groups-option.rst.inc
+
+``minMessage``
+~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.``
+
+This is the message that will be shown if the value does not contain at least
+the minimum number of words.
+
+You can use the following parameters in this message:
+
+================  ==================================================
+Parameter         Description
+================  ==================================================
+``{{ min }}``     The minimum number of words
+``{{ count }}``   The actual number of words
+================  ==================================================
+
+``maxMessage``
+~~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.``
+
+This is the message that will be shown if the value contains more than the
+maximum number of words.
+
+You can use the following parameters in this message:
+
+================  ==================================================
+Parameter         Description
+================  ==================================================
+``{{ max }}``     The maximum number of words
+``{{ count }}``   The actual number of words
+================  ==================================================
+
+.. include:: /reference/constraints/_payload-option.rst.inc
diff --git a/reference/constraints/Yaml.rst b/reference/constraints/Yaml.rst
new file mode 100644
index 00000000000..0d1564f4f8a
--- /dev/null
+++ b/reference/constraints/Yaml.rst
@@ -0,0 +1,152 @@
+Yaml
+====
+
+Validates that a value has valid `YAML`_ syntax.
+
+.. versionadded:: 7.2
+
+    The ``Yaml`` constraint was introduced in Symfony 7.2.
+
+==========  ===================================================================
+Applies to  :ref:`property or method <validation-property-target>`
+Class       :class:`Symfony\\Component\\Validator\\Constraints\\Yaml`
+Validator   :class:`Symfony\\Component\\Validator\\Constraints\\YamlValidator`
+==========  ===================================================================
+
+Basic Usage
+-----------
+
+The ``Yaml`` constraint can be applied to a property or a "getter" method:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/Report.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+
+        class Report
+        {
+            #[Assert\Yaml(
+                message: "Your configuration doesn't have valid YAML syntax."
+            )]
+            private string $customConfiguration;
+        }
+
+    .. code-block:: yaml
+
+        # config/validator/validation.yaml
+        App\Entity\Report:
+            properties:
+                customConfiguration:
+                    - Yaml:
+                        message: Your configuration doesn't have valid YAML syntax.
+
+    .. code-block:: xml
+
+        <!-- config/validator/validation.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
+
+            <class name="App\Entity\Report">
+                <property name="customConfiguration">
+                    <constraint name="Yaml">
+                        <option name="message">Your configuration doesn't have valid YAML syntax.</option>
+                    </constraint>
+                </property>
+            </class>
+        </constraint-mapping>
+
+    .. code-block:: php
+
+        // src/Entity/Report.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+
+        class Report
+        {
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('customConfiguration', new Assert\Yaml(
+                    message: 'Your configuration doesn\'t have valid YAML syntax.',
+                ));
+            }
+        }
+
+Options
+-------
+
+``flags``
+~~~~~~~~~
+
+**type**: ``integer`` **default**: ``0``
+
+This option enables optional features of the YAML parser when validating contents.
+Its value is a combination of one or more of the :ref:`flags defined by the Yaml component <yaml-flags>`:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        // src/Entity/Report.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Yaml\Yaml;
+
+        class Report
+        {
+            #[Assert\Yaml(
+                message: "Your configuration doesn't have valid YAML syntax.",
+                flags: Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_DATETIME,
+            )]
+            private string $customConfiguration;
+        }
+
+    .. code-block:: php
+
+        // src/Entity/Report.php
+        namespace App\Entity;
+
+        use Symfony\Component\Validator\Constraints as Assert;
+        use Symfony\Component\Validator\Mapping\ClassMetadata;
+        use Symfony\Component\Yaml\Yaml;
+
+        class Report
+        {
+            public static function loadValidatorMetadata(ClassMetadata $metadata): void
+            {
+                $metadata->addPropertyConstraint('customConfiguration', new Assert\Yaml(
+                    message: 'Your configuration doesn\'t have valid YAML syntax.',
+                    flags: Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_DATETIME,
+                ));
+            }
+        }
+
+``message``
+~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``This value is not valid YAML.``
+
+This message shown if the underlying data is not a valid YAML value.
+
+You can use the following parameters in this message:
+
+===============  ==============================================================
+Parameter        Description
+===============  ==============================================================
+``{{ error }}``  The full error message from the YAML parser
+``{{ line }}``   The line where the YAML syntax error happened
+===============  ==============================================================
+
+.. include:: /reference/constraints/_groups-option.rst.inc
+
+.. include:: /reference/constraints/_payload-option.rst.inc
+
+.. _`YAML`: https://en.wikipedia.org/wiki/YAML
diff --git a/reference/constraints/_comparison-value-option.rst.inc b/reference/constraints/_comparison-value-option.rst.inc
index c8abdfb5af0..91ab28a2e94 100644
--- a/reference/constraints/_comparison-value-option.rst.inc
+++ b/reference/constraints/_comparison-value-option.rst.inc
@@ -1,7 +1,7 @@
 ``value``
 ~~~~~~~~~
 
-**type**: ``mixed`` [:ref:`default option <validation-default-option>`]
+**type**: ``mixed``
 
 This option is required. It defines the comparison value. It can be a
 string, number or object.
diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc
index 3b77428ed05..06680e42207 100644
--- a/reference/constraints/map.rst.inc
+++ b/reference/constraints/map.rst.inc
@@ -19,6 +19,7 @@ String Constraints
 
 .. class:: ui-list-three-columns
 
+* :doc:`Charset </reference/constraints/Charset>`
 * :doc:`Cidr </reference/constraints/Cidr>`
 * :doc:`CssColor </reference/constraints/CssColor>`
 * :doc:`Email </reference/constraints/Email>`
@@ -27,14 +28,18 @@ String Constraints
 * :doc:`Ip </reference/constraints/Ip>`
 * :doc:`Json </reference/constraints/Json>`
 * :doc:`Length </reference/constraints/Length>`
+* :doc:`MacAddress </reference/constraints/MacAddress>`
 * :doc:`NoSuspiciousCharacters </reference/constraints/NoSuspiciousCharacters>`
 * :doc:`NotCompromisedPassword </reference/constraints/NotCompromisedPassword>`
 * :doc:`PasswordStrength </reference/constraints/PasswordStrength>`
 * :doc:`Regex </reference/constraints/Regex>`
+* :doc:`Twig </reference/constraints/Twig>`
 * :doc:`Ulid </reference/constraints/Ulid>`
 * :doc:`Url </reference/constraints/Url>`
 * :doc:`UserPassword </reference/constraints/UserPassword>`
 * :doc:`Uuid </reference/constraints/Uuid>`
+* :doc:`WordCount </reference/constraints/WordCount>`
+* :doc:`Yaml </reference/constraints/Yaml>`
 
 Comparison Constraints
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -68,6 +73,7 @@ Date Constraints
 * :doc:`DateTime </reference/constraints/DateTime>`
 * :doc:`Time </reference/constraints/Time>`
 * :doc:`Timezone </reference/constraints/Timezone>`
+* :doc:`Week </reference/constraints/Week>`
 
 Choice Constraints
 ~~~~~~~~~~~~~~~~~~
diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst
index 0c5a4fe1e26..866aac5774f 100644
--- a/reference/dic_tags.rst
+++ b/reference/dic_tags.rst
@@ -337,13 +337,6 @@ Value resolvers implement the
 and are used to resolve argument values for controllers as described here:
 :doc:`/controller/value_resolver`.
 
-.. versionadded:: 6.2
-
-    The ``ValueResolverInterface`` was introduced in Symfony 6.2. Prior to
-    6.2, you had to use the
-    :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface`,
-    which defines different methods.
-
 data_collector
 --------------
 
@@ -519,12 +512,6 @@ If you don't need to preload anything, return an empty array. If read-only
 artifacts need to be created, you can store them in a different directory
 with the ``$buildDir`` parameter of the ``warmUp()`` method.
 
-.. versionadded:: 6.4
-
-    The ``$buildDir`` parameter of the
-    :method:`Symfony\\Component\\HttpKernel\\CacheWarmer\\WarmableInterface::warmUp`
-    method was introduced in Symfony 6.4.
-
 The ``isOptional()`` method should return true if it's possible to use the
 application without calling this cache warmer. In Symfony, optional warmers
 are always executed by default (you can change this by using the
@@ -1079,23 +1066,16 @@ file
 
 When executing the ``translation:extract`` command, it uses extractors to
 extract translation messages from a file. By default, the Symfony Framework
-has a :class:`Symfony\\Bridge\\Twig\\Translation\\TwigExtractor` and a PHP
-extractor to find and extract translation keys from Twig templates and PHP files.
+has a :class:`Symfony\\Bridge\\Twig\\Translation\\TwigExtractor` to find and
+extract translation keys from Twig templates.
 
-Symfony includes two PHP extractors: :class:`Symfony\\Component\\Translation\\Extractor\\PhpExtractor`
-and :class:`Symfony\\Component\\Translation\\Extractor\\PhpAstExtractor`. The
-first one is simple but doesn't require to install any packages; the second one
-is much more advanced, but requires to install this dependency in your project:
+If you also want to find and extract translation keys from PHP files, install
+the following dependency to activate the :class:`Symfony\\Component\\Translation\\Extractor\\PhpAstExtractor`:
 
 .. code-block:: terminal
 
     $ composer require nikic/php-parser
 
-.. deprecated:: 6.2
-
-    The ``PhpExtractor`` class is deprecated since Symfony 6.2. The ``PhpAstExtractor``
-    class will be the only PHP extractor available starting from Symfony 7.0.
-
 You can create your own extractor by creating a class that implements
 :class:`Symfony\\Component\\Translation\\Extractor\\ExtractorInterface`
 and tagging the service with ``translation.extractor``. The tag has one
diff --git a/reference/events.rst b/reference/events.rst
index 411e5e327f5..57806ee8f8d 100644
--- a/reference/events.rst
+++ b/reference/events.rst
@@ -56,8 +56,8 @@ their priorities:
 
 This event is dispatched after the controller has been resolved but before executing
 it. It's useful to initialize things later needed by the
-controller, such as `value resolvers`_, and even to change the controller
-entirely::
+controller, such as :ref:`value resolvers <managing-value-resolvers>`, and
+even to change the controller entirely::
 
     use Symfony\Component\HttpKernel\Event\ControllerEvent;
 
@@ -296,5 +296,3 @@ their priorities:
 .. code-block:: terminal
 
     $ php bin/console debug:event-dispatcher kernel.exception
-
-.. _`value resolvers`: https://symfony.com/doc/current/controller/value_resolver.html#managing-value-resolvers
diff --git a/reference/formats/expression_language.rst b/reference/formats/expression_language.rst
index 9052b2f9520..02d36ba318f 100644
--- a/reference/formats/expression_language.rst
+++ b/reference/formats/expression_language.rst
@@ -20,11 +20,11 @@ The component supports:
 * **booleans** - ``true`` and ``false``
 * **null** - ``null``
 * **exponential** - also known as scientific (e.g. ``1.99E+3`` or ``1e-2``)
+* **comments** - using ``/*`` and ``*/`` (e.g. ``/* this is a comment */``)
 
-.. versionadded:: 6.1
+.. versionadded:: 7.2
 
-    Support for decimals without leading zeros and underscore separators were
-    introduced in Symfony 6.1.
+    The support for comments inside expressions was introduced in Symfony 7.2.
 
 .. warning::
 
@@ -116,10 +116,6 @@ operator)::
     $expressionLanguage->evaluate('fruit?.color', ['fruit' => '...'])
     $expressionLanguage->evaluate('fruit?.getStock()', ['fruit' => '...'])
 
-.. versionadded:: 6.1
-
-    The null safe operator was introduced in Symfony 6.1.
-
 .. _component-expression-null-coalescing-operator:
 
 Null-Coalescing Operator
@@ -133,15 +129,10 @@ returns the right-hand side. Expressions can chain multiple coalescing operators
 * ``foo[3] ?? 'no'``
 * ``foo.baz ?? foo['baz'] ?? 'no'``
 
-.. note::
-
-    The main difference with the `null-coalescing operator in PHP`_ is that
-    ExpressionLanguage will throw an exception when trying to access a
-    non-existent variable.
+.. versionadded:: 7.2
 
-.. versionadded:: 6.2
-
-    The null-coalescing operator was introduced in Symfony 6.2.
+    Starting from Symfony 7.2, no exception is thrown when trying to access a
+    non-existent variable. This is the same behavior as the `null-coalescing operator in PHP`_.
 
 .. _component-expression-functions:
 
@@ -154,6 +145,8 @@ following functions by default:
 
 * ``constant()``
 * ``enum()``
+* ``min()``
+* ``max()``
 
 ``constant()`` function
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -201,9 +194,37 @@ This function will return the case of an enumeration::
 
 This will print out ``true``.
 
-.. versionadded:: 6.3
+``min()`` function
+~~~~~~~~~~~~~~~~~~
 
-    The ``enum()`` function was introduced in Symfony 6.3.
+This function will return the lowest value of the given parameters. You can pass
+different types of parameters (e.g. dates, strings, numeric values) and even mix
+them (e.g. pass numeric values and strings). Internally it uses the :phpfunction:`min`
+PHP function to find the lowest value::
+
+    var_dump($expressionLanguage->evaluate(
+        'min(1, 2, 3)'
+    ));
+
+This will print out ``1``.
+
+``max()`` function
+~~~~~~~~~~~~~~~~~~
+
+This function will return the highest value of the given parameters. You can pass
+different types of parameters (e.g. dates, strings, numeric values) and even mix
+them (e.g. pass numeric values and strings). Internally it uses the :phpfunction:`max`
+PHP function to find the highest value::
+
+    var_dump($expressionLanguage->evaluate(
+        'max(1, 2, 3)'
+    ));
+
+This will print out ``3``.
+
+.. versionadded:: 7.1
+
+    The ``min()`` and ``max()`` functions were introduced in Symfony 7.1.
 
 .. tip::
 
@@ -263,6 +284,14 @@ Bitwise Operators
 * ``&`` (and)
 * ``|`` (or)
 * ``^`` (xor)
+* ``~`` (not)
+* ``<<`` (left shift)
+* ``>>`` (right shift)
+
+.. versionadded:: 7.2
+
+    Support for the ``~``, ``<<`` and ``>>`` bitwise operators was introduced
+    in Symfony 7.2.
 
 Comparison Operators
 ~~~~~~~~~~~~~~~~~~~~
@@ -280,11 +309,6 @@ Comparison Operators
 * ``starts with``
 * ``ends with``
 
-.. versionadded:: 6.1
-
-    The ``contains``, ``starts with`` and ``ends with`` operators were introduced
-    in Symfony 6.1.
-
 .. tip::
 
     To test if a string does *not* match a regex, use the logical ``not``
@@ -321,6 +345,11 @@ Logical Operators
 * ``not`` or ``!``
 * ``and`` or ``&&``
 * ``or`` or ``||``
+* ``xor``
+
+.. versionadded:: 7.2
+
+    Support for the ``xor`` logical operator was introduced in Symfony 7.2.
 
 For example::
 
@@ -358,7 +387,7 @@ Array Operators
 * ``in`` (contain)
 * ``not in`` (does not contain)
 
-For example::
+These operators are using strict comparison. For example::
 
     class User
     {
@@ -377,12 +406,9 @@ For example::
 
 The ``$inGroup`` would evaluate to ``true``.
 
-.. deprecated:: 6.3
+.. note::
 
-    In Symfony versions previous to 6.3, ``in`` and ``not in`` operators
-    were using loose comparison. Using these operators with variables of
-    different types is now deprecated, and these operators will be using
-    strict comparison from Symfony 7.0.
+    The ``in`` and ``not in`` operators are using strict comparison.
 
 Numeric Operators
 ~~~~~~~~~~~~~~~~~
@@ -436,38 +462,40 @@ parentheses in your expressions (e.g. ``(1 + 2) * 4`` or ``1 + (2 * 4)``.
 The following table summarizes the operators and their associativity from the
 **highest to the lowest precedence**:
 
-+----------------------------------------------------------+---------------+
-| Operators                                                | Associativity |
-+==========================================================+===============+
-| ``-`` , ``+`` (unary operators that add the number sign) | none          |
-+----------------------------------------------------------+---------------+
-| ``**``                                                   | right         |
-+----------------------------------------------------------+---------------+
-| ``*``, ``/``, ``%``                                      | left          |
-+----------------------------------------------------------+---------------+
-| ``not``, ``!``                                           | none          |
-+----------------------------------------------------------+---------------+
-| ``~``                                                    | left          |
-+----------------------------------------------------------+---------------+
-| ``+``, ``-``                                             | left          |
-+----------------------------------------------------------+---------------+
-| ``..``                                                   | left          |
-+----------------------------------------------------------+---------------+
-| ``==``, ``===``, ``!=``, ``!==``,                        | left          |
-| ``<``, ``>``, ``>=``, ``<=``,                            |               |
-| ``not in``, ``in``, ``contains``,                        |               |
-| ``starts with``, ``ends with``, ``matches``              |               |
-+----------------------------------------------------------+---------------+
-| ``&``                                                    | left          |
-+----------------------------------------------------------+---------------+
-| ``^``                                                    | left          |
-+----------------------------------------------------------+---------------+
-| ``|``                                                    | left          |
-+----------------------------------------------------------+---------------+
-| ``and``, ``&&``                                          | left          |
-+----------------------------------------------------------+---------------+
-| ``or``, ``||``                                           | left          |
-+----------------------------------------------------------+---------------+
++-----------------------------------------------------------------+---------------+
+| Operators                                                       | Associativity |
++=================================================================+===============+
+| ``-`` , ``+``, ``~`` (unary operators that add the number sign) | none          |
++-----------------------------------------------------------------+---------------+
+| ``**``                                                          | right         |
++-----------------------------------------------------------------+---------------+
+| ``*``, ``/``, ``%``                                             | left          |
++-----------------------------------------------------------------+---------------+
+| ``not``, ``!``                                                  | none          |
++-----------------------------------------------------------------+---------------+
+| ``~``                                                           | left          |
++-----------------------------------------------------------------+---------------+
+| ``+``, ``-``                                                    | left          |
++-----------------------------------------------------------------+---------------+
+| ``..``, ``<<``, ``>>``                                          | left          |
++-----------------------------------------------------------------+---------------+
+| ``==``, ``===``, ``!=``, ``!==``,                               | left          |
+| ``<``, ``>``, ``>=``, ``<=``,                                   |               |
+| ``not in``, ``in``, ``contains``,                               |               |
+| ``starts with``, ``ends with``, ``matches``                     |               |
++-----------------------------------------------------------------+---------------+
+| ``&``                                                           | left          |
++-----------------------------------------------------------------+---------------+
+| ``^``                                                           | left          |
++-----------------------------------------------------------------+---------------+
+| ``|``                                                           | left          |
++-----------------------------------------------------------------+---------------+
+| ``and``, ``&&``                                                 | left          |
++-----------------------------------------------------------------+---------------+
+| ``xor``                                                         | left          |
++-----------------------------------------------------------------+---------------+
+| ``or``, ``||``                                                  | left          |
++-----------------------------------------------------------------+---------------+
 
 Built-in Objects and Variables
 ------------------------------
diff --git a/reference/formats/xliff.rst b/reference/formats/xliff.rst
index acb9af36014..b5dc99b4186 100644
--- a/reference/formats/xliff.rst
+++ b/reference/formats/xliff.rst
@@ -29,7 +29,7 @@ loaded/dumped inside a Symfony application:
                     <note category="approved">true</note>
                     <note category="section" priority="1">user login</note>
                 </notes>
-                <segment>
+                <segment state="translated" subState="Some custom value">
                     <source>original-content</source>
                     <target>translated-content</target>
                 </segment>
@@ -37,4 +37,8 @@ loaded/dumped inside a Symfony application:
         </file>
     </xliff>
 
+.. versionadded:: 7.2
+
+    The support of attributes in the ``<segment>`` element was introduced in Symfony 7.2.
+
 .. _XLIFF: https://docs.oasis-open.org/xliff/xliff-core/v2.1/xliff-core-v2.1.html
diff --git a/reference/formats/yaml.rst b/reference/formats/yaml.rst
index 9f73da6bc0c..1884735bd82 100644
--- a/reference/formats/yaml.rst
+++ b/reference/formats/yaml.rst
@@ -344,9 +344,18 @@ official YAML specification but are useful in Symfony applications:
           # ... or you can also use "->value" to directly use the value of a BackedEnum case
           operator_type: !php/enum App\Operator\Enum\Type::Or->value
 
-.. versionadded:: 6.2
+  This tag allows to omit the enum case and only provide the enum FQCN
+  to return an array of all available enum cases:
 
-    The ``!php/enum`` tag was introduced in Symfony 6.2.
+  .. code-block:: yaml
+
+      data:
+          operator_types: !php/enum App\Operator\Enum\Type
+
+  .. versionadded:: 7.1
+
+    The support for using the enum FQCN without specifying a case
+    was introduced in Symfony 7.1.
 
 Unsupported YAML Features
 ~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst
index 2098d3cfb89..383dbf890f2 100644
--- a/reference/forms/types/birthday.rst
+++ b/reference/forms/types/birthday.rst
@@ -19,8 +19,6 @@ option defaults to 120 years ago to the current year.
 +---------------------------+-------------------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid birthdate.                                               |
 +---------------------------+-------------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                           |
-+---------------------------+-------------------------------------------------------------------------------+
 | Parent type               | :doc:`DateType </reference/forms/types/date>`                                 |
 +---------------------------+-------------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\BirthdayType`        |
diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst
index 472d6f84024..2299220c5b6 100644
--- a/reference/forms/types/checkbox.rst
+++ b/reference/forms/types/checkbox.rst
@@ -13,8 +13,6 @@ if you want to handle submitted values like "0" or "false").
 +---------------------------+------------------------------------------------------------------------+
 | Default invalid message   | The checkbox has an invalid value.                                     |
 +---------------------------+------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                    |
-+---------------------------+------------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                          |
 +---------------------------+------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType` |
diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst
index 459ee060efe..9f61fb768bd 100644
--- a/reference/forms/types/choice.rst
+++ b/reference/forms/types/choice.rst
@@ -11,8 +11,6 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op
 +---------------------------+----------------------------------------------------------------------+
 | Default invalid message   | The selected choice is invalid.                                      |
 +---------------------------+----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                  |
-+---------------------------+----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                        |
 +---------------------------+----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType` |
@@ -180,6 +178,8 @@ correct types will be assigned to the model.
 
 .. include:: /reference/forms/types/options/choice_loader.rst.inc
 
+.. include:: /reference/forms/types/options/choice_lazy.rst.inc
+
 .. include:: /reference/forms/types/options/choice_name.rst.inc
 
 .. include:: /reference/forms/types/options/choice_translation_domain_enabled.rst.inc
@@ -202,6 +202,32 @@ correct types will be assigned to the model.
 
 .. include:: /reference/forms/types/options/preferred_choices.rst.inc
 
+``separator``
+~~~~~~~~~~~~~
+
+**type**: ``string`` **default**: ``-------------------``
+
+This option allows you to customize the visual separator shown after the preferred
+choices. You can use HTML elements like ``<hr>`` to display a more modern separator,
+but you'll also need to set the `separator_html`_ option to ``true``.
+
+.. versionadded:: 7.1
+
+    The ``separator`` option was introduced in Symfony 7.1.
+
+``separator_html``
+~~~~~~~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``false``
+
+If this option is true, the `separator`_ option will be displayed as HTML instead
+of text. This is useful when using HTML elements (e.g. ``<hr>``) as a more modern
+visual separator.
+
+.. versionadded:: 7.1
+
+    The ``separator_html`` option was introduced in Symfony 7.1.
+
 Overridden Options
 ------------------
 
diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst
index 229e8ab966f..2875ba076d0 100644
--- a/reference/forms/types/collection.rst
+++ b/reference/forms/types/collection.rst
@@ -16,8 +16,6 @@ that is passed as the collection type field data.
 +---------------------------+--------------------------------------------------------------------------+
 | Default invalid message   | The collection is invalid.                                               |
 +---------------------------+--------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                      |
-+---------------------------+--------------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                            |
 +---------------------------+--------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType` |
@@ -200,10 +198,6 @@ prototype_options
 
 **type**: ``array`` **default**: ``[]``
 
-.. versionadded:: 6.1
-
-    The ``prototype_options`` option was introduced in Symfony 6.1.
-
 This is the array that's passed to the form type specified in the `entry_type`_
 option when creating its prototype. It allows to have different options depending
 on whether you are adding a new entry or editing an existing entry::
@@ -233,6 +227,27 @@ you'd use the :doc:`EmailType </reference/forms/types/email>`. If you want
 to embed a collection of some other form, pass the form type class as this
 option (e.g. ``MyFormType::class``).
 
+keep_as_list
+~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``false``
+
+When set to ``true``, the ``keep_as_list`` option affects the reindexing
+of nested form names within a collection. This feature is particularly useful
+when working with collection types and removing items from the collection
+during form submission.
+
+When this option is set to ``false``, if you have a collection of 3 items and
+you remove the second item, the indexes will be ``0`` and ``2`` when validating
+the collection. However, by enabling the ``keep_as_list`` option and setting
+it to ``true``, the indexes will be reindexed as ``0`` and ``1``. This ensures
+that the indexes remain consecutive and do not have gaps, providing a clearer
+and more predictable structure for your nested forms.
+
+.. versionadded:: 7.1
+
+    The ``keep_as_list`` option was introduced in Symfony 7.1.
+
 prototype
 ~~~~~~~~~
 
diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst
index 1a320b9bdbf..b205127fb91 100644
--- a/reference/forms/types/color.rst
+++ b/reference/forms/types/color.rst
@@ -16,8 +16,6 @@ element.
 +---------------------------+---------------------------------------------------------------------+
 | Default invalid message   | Please select a valid color.                                        |
 +---------------------------+---------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                 |
-+---------------------------+---------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                       |
 +---------------------------+---------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\ColorType` |
diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst
index aa3d8323910..6c98897b6ba 100644
--- a/reference/forms/types/country.rst
+++ b/reference/forms/types/country.rst
@@ -20,8 +20,6 @@ the option manually, but then you should just use the ``ChoiceType`` directly.
 +---------------------------+-----------------------------------------------------------------------+
 | Default invalid message   | Please select a valid country.                                        |
 +---------------------------+-----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                   |
-+---------------------------+-----------------------------------------------------------------------+
 | Parent type               | :doc:`ChoiceType </reference/forms/types/choice>`                     |
 +---------------------------+-----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CountryType` |
diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst
index 9b7affe468c..94c0d2cddc8 100644
--- a/reference/forms/types/currency.rst
+++ b/reference/forms/types/currency.rst
@@ -13,8 +13,6 @@ manually, but then you should just use the ``ChoiceType`` directly.
 +---------------------------+------------------------------------------------------------------------+
 | Default invalid message   | Please select a valid currency.                                        |
 +---------------------------+------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                    |
-+---------------------------+------------------------------------------------------------------------+
 | Parent type               | :doc:`ChoiceType </reference/forms/types/choice>`                      |
 +---------------------------+------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\CurrencyType` |
diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst
index 801bd6323f7..210fff5dd0d 100644
--- a/reference/forms/types/date.rst
+++ b/reference/forms/types/date.rst
@@ -14,8 +14,6 @@ and can understand a number of different input formats via the `input`_ option.
 +---------------------------+-----------------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid date.                                                  |
 +---------------------------+-----------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                         |
-+---------------------------+-----------------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                               |
 +---------------------------+-----------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateType`          |
@@ -155,6 +153,20 @@ values for the year, month and day fields::
 
 .. include:: /reference/forms/types/options/view_timezone.rst.inc
 
+``calendar``
+~~~~~~~~~~~~
+
+**type**: ``integer`` or ``\IntlCalendar`` **default**: ``null``
+
+The calendar to use for formatting and parsing the date. The value should be
+an ``integer`` from :phpclass:`IntlDateFormatter` calendar constants or an instance
+of the :phpclass:`IntlCalendar` to use. By default, the Gregorian calendar
+with the application default locale is used.
+
+.. versionadded:: 7.2
+
+    The ``calendar`` option was introduced in Symfony 7.2.
+
 .. include:: /reference/forms/types/options/date_widget.rst.inc
 
 .. include:: /reference/forms/types/options/years.rst.inc
diff --git a/reference/forms/types/dateinterval.rst b/reference/forms/types/dateinterval.rst
index b317ac522f4..838ae2bbdef 100644
--- a/reference/forms/types/dateinterval.rst
+++ b/reference/forms/types/dateinterval.rst
@@ -16,8 +16,6 @@ or an array (see `input`_).
 +---------------------------+----------------------------------------------------------------------------------+
 | Default invalid message   | Please choose a valid date interval.                                             |
 +---------------------------+----------------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                              |
-+---------------------------+----------------------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                                    |
 +---------------------------+----------------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateIntervalType`       |
diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst
index 7ffc0ee216f..5fda8e9a14f 100644
--- a/reference/forms/types/datetime.rst
+++ b/reference/forms/types/datetime.rst
@@ -14,8 +14,6 @@ the data can be a ``DateTime`` object, a string, a timestamp or an array.
 +---------------------------+-----------------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid date and time.                                         |
 +---------------------------+-----------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                         |
-+---------------------------+-----------------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                               |
 +---------------------------+-----------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\DateTimeType`      |
diff --git a/reference/forms/types/email.rst b/reference/forms/types/email.rst
index 9045bba8cc4..ef535050813 100644
--- a/reference/forms/types/email.rst
+++ b/reference/forms/types/email.rst
@@ -9,8 +9,6 @@ The ``EmailType`` field is a text field that is rendered using the HTML5
 +---------------------------+---------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid email address.                                 |
 +---------------------------+---------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                 |
-+---------------------------+---------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                       |
 +---------------------------+---------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EmailType` |
diff --git a/reference/forms/types/enum.rst b/reference/forms/types/enum.rst
index 6a78004c7ff..b786fb68125 100644
--- a/reference/forms/types/enum.rst
+++ b/reference/forms/types/enum.rst
@@ -10,8 +10,6 @@ field and defines the same options.
 +---------------------------+----------------------------------------------------------------------+
 | Default invalid message   | The selected choice is invalid.                                      |
 +---------------------------+----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                  |
-+---------------------------+----------------------------------------------------------------------+
 | Parent type               | :doc:`ChoiceType </reference/forms/types/choice>`                    |
 +---------------------------+----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\EnumType`   |
@@ -80,10 +78,6 @@ implement ``TranslatableInterface`` to translate or display custom labels::
         }
     }
 
-.. versionadded:: 6.4
-
-    Support for ``TranslatableInterface`` was introduced in Symfony 6.4.
-
 Field Options
 -------------
 
diff --git a/reference/forms/types/file.rst b/reference/forms/types/file.rst
index 95aab73783a..2e841611eb8 100644
--- a/reference/forms/types/file.rst
+++ b/reference/forms/types/file.rst
@@ -8,8 +8,6 @@ The ``FileType`` represents a file input in your form.
 +---------------------------+--------------------------------------------------------------------+
 | Default invalid message   | Please select a valid file.                                        |
 +---------------------------+--------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                |
-+---------------------------+--------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                      |
 +---------------------------+--------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FileType` |
@@ -55,6 +53,10 @@ You might calculate the filename in one of the following ways::
     // use the original file name
     $file->move($directory, $file->getClientOriginalName());
 
+    // when "webkitdirectory" upload was used
+    // otherwise the value will be the same as getClientOriginalName
+    // $file->move($directory, $file->getClientOriginalPath());
+
     // compute a random name and try to guess the extension (more secure)
     $extension = $file->guessExtension();
     if (!$extension) {
@@ -63,9 +65,9 @@ You might calculate the filename in one of the following ways::
     }
     $file->move($directory, rand(1, 99999).'.'.$extension);
 
-Using the original name via ``getClientOriginalName()`` is not safe as it
-could have been manipulated by the end-user. Moreover, it can contain
-characters that are not allowed in file names. You should sanitize the name
+Using the original name via ``getClientOriginalName()`` or ``getClientOriginalPath``
+is not safe as it could have been manipulated by the end-user. Moreover, it can contain
+characters that are not allowed in file names. You should sanitize the value
 before using it directly.
 
 Read :doc:`/controller/upload_file` for an example of how to manage a file
diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst
index 0d0089c1fd3..58a6214d379 100644
--- a/reference/forms/types/form.rst
+++ b/reference/forms/types/form.rst
@@ -7,8 +7,6 @@ on all types for which ``FormType`` is the parent.
 +---------------------------+--------------------------------------------------------------------+
 | Default invalid message   | This value is not valid.                                           |
 +---------------------------+--------------------------------------------------------------------+
-| Legacy invalid message    | This value is not valid.                                           |
-+---------------------------+--------------------------------------------------------------------+
 | Parent                    | none                                                               |
 +---------------------------+--------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType` |
diff --git a/reference/forms/types/hidden.rst b/reference/forms/types/hidden.rst
index fba056b88e5..d6aff282edd 100644
--- a/reference/forms/types/hidden.rst
+++ b/reference/forms/types/hidden.rst
@@ -8,8 +8,6 @@ The hidden type represents a hidden input field.
 +---------------------------+----------------------------------------------------------------------+
 | Default invalid message   | The hidden field is invalid.                                         |
 +---------------------------+----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                  |
-+---------------------------+----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                        |
 +---------------------------+----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\HiddenType` |
diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst
index 619ac996df6..1f94f9e2525 100644
--- a/reference/forms/types/integer.rst
+++ b/reference/forms/types/integer.rst
@@ -15,8 +15,6 @@ integers. By default, all non-integer values (e.g. 6.78) will round down
 +---------------------------+-----------------------------------------------------------------------+
 | Default invalid message   | Please enter an integer.                                              |
 +---------------------------+-----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                   |
-+---------------------------+-----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                         |
 +---------------------------+-----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\IntegerType` |
diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst
index d8f5247856b..a1e699a0686 100644
--- a/reference/forms/types/language.rst
+++ b/reference/forms/types/language.rst
@@ -22,8 +22,6 @@ manually, but then you should just use the ``ChoiceType`` directly.
 +---------------------------+------------------------------------------------------------------------+
 | Default invalid message   | Please select a valid language.                                        |
 +---------------------------+------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                    |
-+---------------------------+------------------------------------------------------------------------+
 | Parent type               | :doc:`ChoiceType </reference/forms/types/choice>`                      |
 +---------------------------+------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LanguageType` |
diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst
index 15b9af8b7fb..c006beb14fd 100644
--- a/reference/forms/types/locale.rst
+++ b/reference/forms/types/locale.rst
@@ -23,8 +23,6 @@ manually, but then you should just use the ``ChoiceType`` directly.
 +---------------------------+----------------------------------------------------------------------+
 | Default invalid message   | Please select a valid locale.                                        |
 +---------------------------+----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                  |
-+---------------------------+----------------------------------------------------------------------+
 | Parent type               | :doc:`ChoiceType </reference/forms/types/choice>`                    |
 +---------------------------+----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\LocaleType` |
diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst
index 1568ec891f9..967fe9e4ce4 100644
--- a/reference/forms/types/money.rst
+++ b/reference/forms/types/money.rst
@@ -13,8 +13,6 @@ how the input and output of the data is handled.
 +---------------------------+---------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid money amount.                                  |
 +---------------------------+---------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                 |
-+---------------------------+---------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                       |
 +---------------------------+---------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\MoneyType` |
@@ -77,6 +75,22 @@ If set to ``true``, the HTML input will be rendered as a native HTML5
     As HTML5 number format is normalized, it is incompatible with the ``grouping``
     option.
 
+input
+~~~~~
+
+**type**: ``string`` **default**: ``float``
+
+By default, the money value is converted to a ``float`` PHP type. If you need the
+value to be converted into an integer (e.g. because some library needs money
+values stored in cents as integers) set this option to ``integer``.
+You can also set this option to ``string``, it can be useful if the underlying
+data is a string for precision reasons (for example, Doctrine uses strings for
+the decimal type).
+
+.. versionadded:: 7.1
+
+    The ``input`` option was introduced in Symfony 7.1.
+
 scale
 ~~~~~
 
diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst
index f88dc5b97f5..7e125a5fd05 100644
--- a/reference/forms/types/number.rst
+++ b/reference/forms/types/number.rst
@@ -10,8 +10,6 @@ that you want to use for your number.
 +---------------------------+----------------------------------------------------------------------+
 | Default invalid message   | Please enter a number.                                               |
 +---------------------------+----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                  |
-+---------------------------+----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                        |
 +---------------------------+----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\NumberType` |
@@ -60,10 +58,6 @@ include an `inputmode HTML attribute`_ which depends on the value of this option
 If the ``scale`` value is ``0``, ``inputmode`` will be ``numeric``; if ``scale``
 is set to any value greater than ``0``, ``inputmode`` will be ``decimal``.
 
-.. versionadded:: 6.1
-
-   The automatic addition of the ``inputmode`` attribute was introduced in Symfony 6.1.
-
 Overridden Options
 ------------------
 
diff --git a/reference/forms/types/options/choice_label.rst.inc b/reference/forms/types/options/choice_label.rst.inc
index 0071498916f..3d83e44da52 100644
--- a/reference/forms/types/options/choice_label.rst.inc
+++ b/reference/forms/types/options/choice_label.rst.inc
@@ -29,12 +29,6 @@ more control::
         },
     ]);
 
-.. versionadded:: 6.2
-
-    Starting from Symfony 6.2, you can use any object that implements
-    :class:`Symfony\\Contracts\\Translation\\TranslatableInterface` as the value
-    of the choice label.
-
 This method is called for *each* choice, passing you the ``$choice`` and
 ``$key`` from the choices array (additional ``$value`` is related to `choice_value`_).
 This will give you:
diff --git a/reference/forms/types/options/choice_lazy.rst.inc b/reference/forms/types/options/choice_lazy.rst.inc
new file mode 100644
index 00000000000..08fbe953e41
--- /dev/null
+++ b/reference/forms/types/options/choice_lazy.rst.inc
@@ -0,0 +1,31 @@
+``choice_lazy``
+~~~~~~~~~~~~~~~
+
+**type**: ``boolean`` **default**: ``false``
+
+.. versionadded:: 7.2
+
+    The ``choice_lazy`` option was introduced in Symfony 7.2.
+
+The ``choice_lazy`` option is particularly useful when dealing with a large set
+of choices, where loading them all at once could cause performance issues or
+delays::
+
+    use App\Entity\User;
+    use Symfony\Bridge\Doctrine\Form\Type\EntityType;
+
+    $builder->add('user', EntityType::class, [
+        'class' => User::class,
+        'choice_lazy' => true,
+    ]);
+
+When set to ``true`` and used alongside the ``choice_loader`` option, the form
+will only load and render the choices that are preset as default values or
+submitted. This defers the loading of the full list of choices, helping to
+improve your form's performance.
+
+.. warning::
+
+    Keep in mind that when using ``choice_lazy``, you are responsible for
+    providing the user interface for selecting choices, typically through a
+    JavaScript plugin capable of dynamically loading choices.
diff --git a/reference/forms/types/options/date_widget_description.rst.inc b/reference/forms/types/options/date_widget_description.rst.inc
index a60a24a3f83..956ad8c7148 100644
--- a/reference/forms/types/options/date_widget_description.rst.inc
+++ b/reference/forms/types/options/date_widget_description.rst.inc
@@ -1,4 +1,4 @@
-**type**: ``string`` **default**: ``choice``
+**type**: ``string`` **default**: ``single_text``
 
 The basic way in which this field should be rendered. Can be one of the
 following:
@@ -10,8 +10,3 @@ following:
 
 * ``single_text``: renders a single input of type ``date``. User's input
   is validated based on the `format`_ option.
-
-.. deprecated:: 6.3
-
-    Not setting a value explicitly for this option is deprecated since Symfony 6.3
-    because the default value will change to ``single_text`` in Symfony 7.0.
diff --git a/reference/forms/types/options/duplicate_preferred_choices.rst.inc b/reference/forms/types/options/duplicate_preferred_choices.rst.inc
index 72e85067bd3..7569d54a21b 100644
--- a/reference/forms/types/options/duplicate_preferred_choices.rst.inc
+++ b/reference/forms/types/options/duplicate_preferred_choices.rst.inc
@@ -20,7 +20,3 @@ option to ``false``, to only display preferred choices at the top of the list::
         'preferred_choices' => ['muppets', 'arr'],
         'duplicate_preferred_choices' => false,
     ]);
-
-.. versionadded:: 6.4
-
-    The ``duplicate_preferred_choices`` option was introduced in Symfony 6.4.
diff --git a/reference/forms/types/options/help.rst.inc b/reference/forms/types/options/help.rst.inc
index 8c9bb5ce917..7d8fcdbec6b 100644
--- a/reference/forms/types/options/help.rst.inc
+++ b/reference/forms/types/options/help.rst.inc
@@ -19,8 +19,3 @@ rendered below the field::
             'help' => new TranslatableMessage('order.status', ['%order_id%' => $order->getId()], 'store'),
         ])
     ;
-
-.. versionadded:: 6.2
-
-    The support for ``TranslatableInterface`` objects as help contents was
-    introduced in Symfony 6.2.
diff --git a/reference/forms/types/options/model_timezone.rst.inc b/reference/forms/types/options/model_timezone.rst.inc
index 44050e89219..0ef0efe1b56 100644
--- a/reference/forms/types/options/model_timezone.rst.inc
+++ b/reference/forms/types/options/model_timezone.rst.inc
@@ -6,10 +6,4 @@
 Timezone that the input data is stored in. This must be one of the
 `PHP supported timezones`_.
 
-.. deprecated:: 6.4
-
-    Starting from Symfony 6.4, it's deprecated to pass ``DateTime`` or ``DateTimeImmutable``
-    values to this form field with a different timezone than the one configured with
-    the ``model_timezone`` option.
-
 .. _`PHP supported timezones`: https://www.php.net/manual/en/timezones.php
diff --git a/reference/forms/types/options/placeholder_attr.rst.inc b/reference/forms/types/options/placeholder_attr.rst.inc
index 49b656cc6df..e537aae8922 100644
--- a/reference/forms/types/options/placeholder_attr.rst.inc
+++ b/reference/forms/types/options/placeholder_attr.rst.inc
@@ -15,7 +15,3 @@ Use this to add additional HTML attributes to the placeholder choice::
             ['title' => 'Choose an option'],
         ],
     ]);
-
-.. versionadded:: 6.3
-
-    The ``placeholder_attr`` option was introduced in Symfony 6.3.
diff --git a/reference/forms/types/options/sanitize_html.rst.inc b/reference/forms/types/options/sanitize_html.rst.inc
index ead1e2791d5..2b5e8a3515b 100644
--- a/reference/forms/types/options/sanitize_html.rst.inc
+++ b/reference/forms/types/options/sanitize_html.rst.inc
@@ -3,10 +3,6 @@ sanitize_html
 
 **type**: ``boolean`` **default**: ``false``
 
-.. versionadded:: 6.1
-
-    The ``sanitize_html`` option was introduced in Symfony 6.1.
-
 When ``true``, the text input will be sanitized using the
 :doc:`Symfony HTML Sanitizer component </html_sanitizer>` after the form is
 submitted. This protects the form input against :ref:`XSS <xss-attacks>`, clickjacking and CSS
diff --git a/reference/forms/types/options/sanitizer.rst.inc b/reference/forms/types/options/sanitizer.rst.inc
index 66a76d591e7..39217653b3c 100644
--- a/reference/forms/types/options/sanitizer.rst.inc
+++ b/reference/forms/types/options/sanitizer.rst.inc
@@ -3,9 +3,5 @@ sanitizer
 
 **type**: ``string`` **default**: ``"default"``
 
-.. versionadded:: 6.1
-
-    The ``sanitizer`` option was introduced in Symfony 6.1.
-
 When `sanitize_html`_ is enabled, you can specify the name of a
 :ref:`custom sanitizer <html-sanitizer-configuration>` using this option.
diff --git a/reference/forms/types/password.rst b/reference/forms/types/password.rst
index bd8ac19a061..59e40fb19d1 100644
--- a/reference/forms/types/password.rst
+++ b/reference/forms/types/password.rst
@@ -8,8 +8,6 @@ The ``PasswordType`` field renders an input password text box.
 +---------------------------+------------------------------------------------------------------------+
 | Default invalid message   | The password is invalid.                                               |
 +---------------------------+------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                    |
-+---------------------------+------------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                          |
 +---------------------------+------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PasswordType` |
@@ -37,10 +35,6 @@ entered into the box, set this to false and submit the form.
 
 **type**: ``string`` **default**: ``null``
 
-.. versionadded:: 6.2
-
-    The ``hash_property_path`` option was introduced in Symfony 6.2.
-
 If set, the password will be hashed using the
 :doc:`PasswordHasher component </security/passwords>` and stored in the
 property defined by the given :doc:`PropertyAccess expression </components/property_access>`.
diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst
index ce985488c76..b46ca298c53 100644
--- a/reference/forms/types/percent.rst
+++ b/reference/forms/types/percent.rst
@@ -14,8 +14,6 @@ the input.
 +---------------------------+-----------------------------------------------------------------------+
 | Default invalid message   | Please enter a percentage value.                                      |
 +---------------------------+-----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                   |
-+---------------------------+-----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                         |
 +---------------------------+-----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\PercentType` |
diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst
index 7702b87cbad..7ab90086803 100644
--- a/reference/forms/types/radio.rst
+++ b/reference/forms/types/radio.rst
@@ -15,8 +15,6 @@ If you want to have a boolean field, use :doc:`CheckboxType </reference/forms/ty
 +---------------------------+---------------------------------------------------------------------+
 | Default invalid message   | Please select a valid option.                                       |
 +---------------------------+---------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                 |
-+---------------------------+---------------------------------------------------------------------+
 | Parent type               | :doc:`CheckboxType </reference/forms/types/checkbox>`               |
 +---------------------------+---------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` |
diff --git a/reference/forms/types/range.rst b/reference/forms/types/range.rst
index 294023ce0c6..06eebfd5473 100644
--- a/reference/forms/types/range.rst
+++ b/reference/forms/types/range.rst
@@ -9,8 +9,6 @@ The ``RangeType`` field is a slider that is rendered using the HTML5
 +---------------------------+---------------------------------------------------------------------+
 | Default invalid message   | Please choose a valid range.                                        |
 +---------------------------+---------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                 |
-+---------------------------+---------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                       |
 +---------------------------+---------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RangeType` |
diff --git a/reference/forms/types/repeated.rst b/reference/forms/types/repeated.rst
index e5bd0cd4520..36211237bbd 100644
--- a/reference/forms/types/repeated.rst
+++ b/reference/forms/types/repeated.rst
@@ -11,8 +11,6 @@ accuracy.
 +---------------------------+------------------------------------------------------------------------+
 | Default invalid message   | The values do not match.                                               |
 +---------------------------+------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                    |
-+---------------------------+------------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                          |
 +---------------------------+------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RepeatedType` |
diff --git a/reference/forms/types/search.rst b/reference/forms/types/search.rst
index 32db9b3eccb..ad4a8f7978a 100644
--- a/reference/forms/types/search.rst
+++ b/reference/forms/types/search.rst
@@ -9,8 +9,6 @@ special functionality supported by some browsers.
 +---------------------------+----------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid search term.                                    |
 +---------------------------+----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                  |
-+---------------------------+----------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                        |
 +---------------------------+----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\SearchType` |
diff --git a/reference/forms/types/tel.rst b/reference/forms/types/tel.rst
index 675f8e3f5cd..e8ab9c322fe 100644
--- a/reference/forms/types/tel.rst
+++ b/reference/forms/types/tel.rst
@@ -15,8 +15,6 @@ to input phone numbers.
 +---------------------------+-------------------------------------------------------------------+
 | Default invalid message   | Please provide a valid phone number.                              |
 +---------------------------+-------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                               |
-+---------------------------+-------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                     |
 +---------------------------+-------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TelType` |
diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst
index f6a612844be..a3378f948cd 100644
--- a/reference/forms/types/time.rst
+++ b/reference/forms/types/time.rst
@@ -14,8 +14,6 @@ stored as a ``DateTime`` object, a string, a timestamp or an array.
 +---------------------------+-----------------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid time.                                                  |
 +---------------------------+-----------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                         |
-+---------------------------+-----------------------------------------------------------------------------+
 | Parent type               | FormType                                                                    |
 +---------------------------+-----------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimeType`          |
diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst
index ceb72eb6979..d2af713f1c8 100644
--- a/reference/forms/types/timezone.rst
+++ b/reference/forms/types/timezone.rst
@@ -16,8 +16,6 @@ manually, but then you should just use the ``ChoiceType`` directly.
 +---------------------------+------------------------------------------------------------------------+
 | Default invalid message   | Please select a valid timezone.                                        |
 +---------------------------+------------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                    |
-+---------------------------+------------------------------------------------------------------------+
 | Parent type               | :doc:`ChoiceType </reference/forms/types/choice>`                      |
 +---------------------------+------------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\TimezoneType` |
diff --git a/reference/forms/types/ulid.rst b/reference/forms/types/ulid.rst
index 52bdb8eb136..71fb77cffa0 100644
--- a/reference/forms/types/ulid.rst
+++ b/reference/forms/types/ulid.rst
@@ -9,8 +9,6 @@ a proper :ref:`Ulid object <ulid>` when submitting the form.
 +---------------------------+-----------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid ULID.                                            |
 +---------------------------+-----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                   |
-+---------------------------+-----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                         |
 +---------------------------+-----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UlidType`    |
diff --git a/reference/forms/types/url.rst b/reference/forms/types/url.rst
index cba961aa8b7..9c6dde6072e 100644
--- a/reference/forms/types/url.rst
+++ b/reference/forms/types/url.rst
@@ -10,8 +10,6 @@ have a protocol.
 +---------------------------+-------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid URL.                                         |
 +---------------------------+-------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                               |
-+---------------------------+-------------------------------------------------------------------+
 | Parent type               | :doc:`TextType </reference/forms/types/text>`                     |
 +---------------------------+-------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UrlType` |
@@ -38,6 +36,11 @@ If a value is submitted that doesn't begin with some protocol (e.g. ``http://``,
 ``ftp://``, etc), this protocol will be prepended to the string when
 the data is submitted to the form.
 
+.. deprecated:: 7.1
+
+    Not setting the ``default_protocol`` option is deprecated since Symfony 7.1
+    and will default to ``null`` in Symfony 8.0.
+
 Overridden Options
 ------------------
 
diff --git a/reference/forms/types/uuid.rst b/reference/forms/types/uuid.rst
index c5aa6c2fdde..664c446bba9 100644
--- a/reference/forms/types/uuid.rst
+++ b/reference/forms/types/uuid.rst
@@ -9,8 +9,6 @@ a proper :ref:`Uuid object <uuid>` when submitting the form.
 +---------------------------+-----------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid UUID.                                            |
 +---------------------------+-----------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                   |
-+---------------------------+-----------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                         |
 +---------------------------+-----------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\UuidType`    |
diff --git a/reference/forms/types/week.rst b/reference/forms/types/week.rst
index 84ee98aff85..bcd39249015 100644
--- a/reference/forms/types/week.rst
+++ b/reference/forms/types/week.rst
@@ -14,8 +14,6 @@ the data can be a string or an array.
 +---------------------------+--------------------------------------------------------------------+
 | Default invalid message   | Please enter a valid week.                                         |
 +---------------------------+--------------------------------------------------------------------+
-| Legacy invalid message    | The value {{ value }} is not valid.                                |
-+---------------------------+--------------------------------------------------------------------+
 | Parent type               | :doc:`FormType </reference/forms/types/form>`                      |
 +---------------------------+--------------------------------------------------------------------+
 | Class                     | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\WeekType` |
diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst
index 8ad72575e82..633d4c7f0c6 100644
--- a/reference/twig_reference.rst
+++ b/reference/twig_reference.rst
@@ -187,20 +187,41 @@ is_granted
 
 .. code-block:: twig
 
-    {{ is_granted(role, object = null, field = null) }}
+    {{ is_granted(role, object = null) }}
 
 ``role``
     **type**: ``string``
 ``object`` *(optional)*
     **type**: ``object``
-``field`` *(optional)*
-    **type**: ``string``
 
 Returns ``true`` if the current user has the given role.
 
 Optionally, an object can be passed to be used by the voter. More information
 can be found in :ref:`security-template`.
 
+is_granted_for_user
+~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 7.3
+
+    The ``is_granted_for_user()`` function was introduced in Symfony 7.3.
+
+.. code-block:: twig
+
+    {{ is_granted_for_user(user, attribute, subject = null) }}
+
+``user``
+    **type**: ``object``
+``attribute``
+    **type**: ``string``
+``subject`` *(optional)*
+    **type**: ``object``
+
+Returns ``true`` if the user is authorized for the specified attribute.
+
+Optionally, an object can be passed to be used by the voter. More information
+can be found in :ref:`security-template`.
+
 logout_path
 ~~~~~~~~~~~
 
@@ -404,10 +425,6 @@ Generates a URL that you can visit to
 :doc:`impersonate a user </security/impersonating_user>`, identified by the
 ``identifier`` argument.
 
-.. versionadded:: 6.4
-
-    The ``impersonation_path()`` function was introduced in Symfony 6.4.
-
 impersonation_url
 ~~~~~~~~~~~~~~~~~
 
@@ -421,10 +438,6 @@ impersonation_url
 It's similar to the `impersonation_path`_ function, but it generates
 absolute URLs instead of relative URLs.
 
-.. versionadded:: 6.4
-
-    The ``impersonation_url()`` function was introduced in Symfony 6.4.
-
 impersonation_exit_path
 ~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -531,6 +544,7 @@ explained in the article about :doc:`customizing form rendering </form/form_cust
 * :ref:`form_row() <reference-forms-twig-row>`
 * :ref:`form_rest() <reference-forms-twig-rest>`
 * :ref:`field_name() <reference-forms-twig-field-helpers>`
+* :ref:`field_id() <reference-forms-twig-field-helpers>`
 * :ref:`field_value() <reference-forms-twig-field-helpers>`
 * :ref:`field_label() <reference-forms-twig-field-helpers>`
 * :ref:`field_help() <reference-forms-twig-field-helpers>`
@@ -627,10 +641,6 @@ Using the filter will be rendered as:
 sanitize_html
 ~~~~~~~~~~~~~
 
-.. versionadded:: 6.1
-
-    The ``sanitize_html()`` filter was introduced in Symfony 6.1.
-
 .. code-block:: twig
 
     {{ body|sanitize_html(sanitizer = "default") }}
@@ -995,6 +1005,37 @@ For example::
     }) }}
     {# output: {"foo":"bar","content":{},"createdAt":"Sat, 2024-11-30"} #}
 
+.. _reference-twig-filter-emojify:
+
+emojify
+~~~~~~~
+
+.. versionadded:: 7.1
+
+    The ``emojify`` filter was introduced in Symfony 7.1.
+
+.. code-block:: twig
+
+    {{ text|emojify(catalog = null) }}
+
+``text``
+    **type**: ``string``
+
+``catalog`` *(optional)*
+    **type**: ``string`` | ``null``
+
+    The emoji set used to generate the textual representation (``slack``,
+    ``github``, ``gitlab``, etc.)
+
+It transforms the textual representation of an emoji (e.g. ``:wave:``) into the
+actual emoji (👋):
+
+.. code-block:: twig
+
+    {{ ':+1:'|emojify }}                 {# renders: 👍 #}
+    {{ ':+1:'|emojify('github') }}       {# renders: 👍 #}
+    {{ ':thumbsup:'|emojify('gitlab') }} {# renders: 👍 #}
+
 .. _reference-twig-tags:
 
 Tags
diff --git a/routing.rst b/routing.rst
index 102aef454f0..9925b323304 100644
--- a/routing.rst
+++ b/routing.rst
@@ -18,12 +18,13 @@ your favorite.
 :ref:`Symfony recommends attributes <best-practice-controller-attributes>`
 because it's convenient to put the route and controller in the same place.
 
+.. _routing-route-attributes:
+
 Creating Routes as Attributes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 PHP attributes allow you to define routes next to the code of the
-:doc:`controllers </controller>` associated to those routes. Attributes are
-native in PHP 8 and higher versions, so you can use them right away.
+:doc:`controllers </controller>` associated to those routes.
 
 You need to add a bit of configuration to your project before using them. If your
 project uses :ref:`Symfony Flex <symfony-flex>`, this file is already created for you.
@@ -48,10 +49,6 @@ classes declared in the ``App\Controller`` namespace and stored in the
 act as a controller too, which is especially useful for small applications that
 use Symfony as a microframework.
 
-.. versionadded:: 6.2
-
-    The feature to import routes from a PSR-4 namespace root was introduced in Symfony 6.2.
-
 Suppose you want to define a route for the ``/blog`` URL in your application. To
 do so, create a :doc:`controller class </controller>` like the following:
 
@@ -438,10 +435,6 @@ can use any of these variables created by Symfony:
     An array of matched :ref:`route parameters <routing-route-parameters>` for
     the current route.
 
-.. versionadded:: 6.1
-
-    The ``params`` variable was introduced in Symfony 6.1.
-
 You can also use these functions:
 
 ``env(string $name)``
@@ -472,11 +465,6 @@ You can also use these functions:
         // Or without alias:
         #[Route(condition: "service('App\\\Service\\\RouteChecker').check(request)")]
 
-.. versionadded:: 6.1
-
-    The ``service(string $alias)`` function and ``#[AsRoutingConditionService]``
-    attribute were introduced in Symfony 6.1.
-
 Behind the scenes, expressions are compiled down to raw PHP. Because of this,
 using the ``condition`` key causes no extra overhead beyond the time it takes
 for the underlying PHP to execute.
@@ -509,6 +497,18 @@ evaluates them:
     blog_show         ANY      ANY      ANY    /blog/{slug}
     ----------------  -------  -------  -----  --------------------------------------------
 
+    # pass this option to also display all the defined route aliases
+    $ php bin/console debug:router --show-aliases
+
+    # pass this option to only display routes that match the given HTTP method
+    # (you can use the special value ANY to see routes that match any method)
+    $ php bin/console debug:router --method=GET
+    $ php bin/console debug:router --method=ANY
+
+.. versionadded:: 7.3
+
+    The ``--method`` option was introduced in Symfony 7.3.
+
 Pass the name (or part of the name) of some route to this argument to print the
 route details:
 
@@ -526,15 +526,6 @@ route details:
     |             | utf8: true                                              |
     +-------------+---------------------------------------------------------+
 
-.. tip::
-
-    Use the ``--show-aliases`` option to show all available aliases for a given
-    route.
-
-.. versionadded:: 6.4
-
-    The ``--show-aliases`` option was introduced in Symfony 6.4.
-
 The other command is called ``router:match`` and it shows which route will match
 the given URL. It's useful to find out why some URL is not executing the
 controller action that you expect:
@@ -773,10 +764,6 @@ URL                       Route          Parameters
                 // ...
             };
 
-    .. versionadded:: 6.1
-
-        The ``Requirement`` enum was introduced in Symfony 6.1.
-
 .. tip::
 
     Route requirements (and route paths too) can include
@@ -790,12 +777,6 @@ URL                       Route          Parameters
     matches any uppercase character in any language, ``\p{Greek}`` matches any
     Greek characters, etc.
 
-.. note::
-
-    When using regular expressions in route parameters, you can set the ``utf8``
-    route option to ``true`` to make any ``.`` character match any UTF-8
-    characters instead of just a single byte.
-
 If you prefer, requirements can be inlined in each parameter using the syntax
 ``{parameter_name<requirements>}``. This feature makes configuration more
 concise, but it can decrease route readability when requirements are complex:
@@ -1070,12 +1051,6 @@ A common routing need is to convert the value stored in some parameter (e.g. an
 integer acting as the user ID) into another value (e.g. the object that
 represents the user). This feature is called a "param converter".
 
-.. versionadded:: 6.2
-
-    Starting from Symfony 6.2, route param conversion is a built-in feature.
-    In previous Symfony versions you had to install the package
-    ``sensio/framework-extra-bundle`` before using this feature.
-
 Now, keep the previous route configuration, but change the arguments of the
 controller action. Instead of ``string $slug``, add ``BlogPost $post``::
 
@@ -1091,7 +1066,7 @@ controller action. Instead of ``string $slug``, add ``BlogPost $post``::
     {
         // ...
 
-        #[Route('/blog/{slug}', name: 'blog_show')]
+        #[Route('/blog/{slug:post}', name: 'blog_show')]
         public function show(BlogPost $post): Response
         {
             // $post is the object whose slug matches the routing parameter
@@ -1105,17 +1080,41 @@ this case), the "param converter" makes a database request to find the object
 using the request parameters (``slug`` in this case). If no object is found,
 Symfony generates a 404 response automatically.
 
+The ``{slug:post}`` syntax maps the route parameter named ``slug`` to the controller
+argument named ``$post``. It also hints the "param converter" to look up the
+corresponding ``BlogPost`` object from the database using the slug.
+
+.. versionadded:: 7.1
+
+    Route parameter mapping was introduced in Symfony 7.1.
+
+When mapping multiple entities from route parameters, name collisions can occur.
+In this example, the route tries to define two mappings: one for an author and one
+for a category; both using the same ``name`` parameter. This isn't allowed because
+the route ends up declaring ``name`` twice::
+
+    #[Route('/search-book/{name:author}/{name:category}')]
+
+Such routes should instead be defined using the following syntax::
+
+    #[Route('/search-book/{authorName:author.name}/{categoryName:category.name}')]
+
+This way, the route parameter names are unique (``authorName`` and ``categoryName``),
+and the "param converter" can correctly map them to controller arguments (``$author``
+and ``$category``), loading them both by their name.
+
+.. versionadded:: 7.3
+
+    This more advanced style of route parameter mapping was introduced in Symfony 7.3.
+
+More advanced mappings can be achieved using the ``#[MapEntity]`` attribute.
 Check out the :ref:`Doctrine param conversion documentation <doctrine-entity-value-resolver>`
-to learn about the ``#[MapEntity]`` attribute that can be used to customize the
-database queries used to fetch the object from the route parameter.
+to learn how to customize the database queries used to fetch the object from the route
+parameter.
 
 Backed Enum Parameters
 ~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    The support of ``\BackedEnum`` as route parameters was introduced Symfony 6.3.
-
 You can use PHP `backed enumerations`_ as route parameters because Symfony will
 convert them automatically to their scalar values.
 
@@ -1409,6 +1408,23 @@ have been renamed. Let's say you have a route called ``product_show``:
 
 .. configuration-block::
 
+    .. code-block:: php-attributes
+
+        // src/Controller/ProductController.php
+        namespace App\Controller;
+
+        use Symfony\Component\HttpFoundation\Response;
+        use Symfony\Component\Routing\Attribute\Route;
+
+        class ProductController
+        {
+            #[Route('/product/{id}', name: 'product_show')]
+            public function show(): Response
+            {
+                // ...
+            }
+        }
+
     .. code-block:: yaml
 
         # config/routes.yaml
@@ -1445,6 +1461,25 @@ Instead of duplicating the original route, you can create an alias for it.
 
 .. configuration-block::
 
+    .. code-block:: php-attributes
+
+        // src/Controller/ProductController.php
+        namespace App\Controller;
+
+        use Symfony\Component\HttpFoundation\Response;
+        use Symfony\Component\Routing\Attribute\Route;
+
+        class ProductController
+        {
+            // the "alias" argument assigns an alternate name to this route;
+            // the alias will point to the actual route "product_show"
+            #[Route('/product/{id}', name: 'product_show', alias: ['product_details'])]
+            public function show(): Response
+            {
+                // ...
+            }
+        }
+
     .. code-block:: yaml
 
         # config/routes.yaml
@@ -1482,9 +1517,22 @@ Instead of duplicating the original route, you can create an alias for it.
             $routes->alias('product_details', 'product_show');
         };
 
+.. versionadded:: 7.3
+
+    Support for route aliases in PHP attributes was introduced in Symfony 7.3.
+
 In this example, both ``product_show`` and ``product_details`` routes can
 be used in the application and will produce the same result.
 
+.. note::
+
+    YAML, XML, and PHP configuration formats are the only ways to define an alias
+    for a route that you do not own. You can't do this when using PHP attributes.
+
+    This allows you for example to use your own route name for URL generation,
+    while still targeting a route defined by a third-party bundle. The alias and
+    the original route do not need to be declared in the same file or format.
+
 .. _routing-alias-deprecation:
 
 Deprecating Route Aliases
@@ -1505,6 +1553,43 @@ This way, the ``product_show`` alias could be deprecated.
 
 .. configuration-block::
 
+    .. code-block:: php-attributes
+
+        // src/Controller/ProductController.php
+        namespace App\Controller;
+
+        use Symfony\Component\HttpFoundation\Response;
+        use Symfony\Component\Routing\Attribute\DeprecatedAlias;
+        use Symfony\Component\Routing\Attribute\Route;
+
+        class ProductController
+        {
+            // this outputs the following generic deprecation message:
+            // Since acme/package 1.2: The "product_show" route alias is deprecated. You should stop using it, as it will be removed in the future.
+            #[Route('/product/{id}',
+                name: 'product_details',
+                alias: new DeprecatedAlias(
+                    aliasName: 'product_show',
+                    package: 'acme/package',
+                    version: '1.2',
+                ),
+            )]
+            // Or, you can also define a custom deprecation message (%alias_id% placeholder is available)
+            #[Route('/product/{id}',
+                name: 'product_details',
+                alias: new DeprecatedAlias(
+                    aliasName: 'product_show',
+                    package: 'acme/package',
+                    version: '1.2',
+                    message: 'The "%alias_id%" route alias is deprecated. Please use "product_details" instead.',
+                ),
+            )]
+            public function show(): Response
+            {
+                // ...
+            }
+        }
+
     .. code-block:: yaml
 
         # Move the concrete route definition under ``product_details``
@@ -1576,6 +1661,10 @@ This way, the ``product_show`` alias could be deprecated.
             )
         ;
 
+.. versionadded:: 7.3
+
+    The ``DeprecatedAlias`` class for PHP attributes was introduced in Symfony 7.3.
+
 In this example, every time the ``product_show`` alias is used, a deprecation
 warning is triggered, advising you to stop using this route and prefer using ``product_details``.
 
@@ -1815,13 +1904,6 @@ In templates, use the :ref:`Twig global app variable <twig-app-variable>`
 to get the current route name (``app.current_route``) and its parameters
 (``app.current_route_parameters``).
 
-.. versionadded:: 6.2
-
-    The ``app.current_route`` and ``app.current_route_parameters`` variables
-    were introduced in Symfony 6.2.
-    Before you had to access ``_route`` and ``_route_params`` request
-    attributes using ``app.request.attributes.get()``.
-
 Special Routes
 --------------
 
@@ -2475,11 +2557,6 @@ that defines only one route. Consider the following class::
 
 Symfony will add a route alias named ``App\Controller\MainController::homepage``.
 
-.. versionadded:: 6.4
-
-    The automatic declaration of route aliases based on FQCNs was introduced in
-    Symfony 6.4.
-
 Generating URLs in Controllers
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2663,23 +2740,23 @@ The solution is to configure the ``default_uri`` option to define the
 
 Now you'll get the expected results when generating URLs in your commands::
 
-    // src/Command/SomeCommand.php
+    // src/Command/MyCommand.php
     namespace App\Command;
 
-    use Symfony\Component\Console\Command\Command;
-    use Symfony\Component\Console\Input\InputInterface;
-    use Symfony\Component\Console\Output\OutputInterface;
+    use Symfony\Component\Console\Attribute\AsCommand;
+    use Symfony\Component\Console\Style\SymfonyStyle;
     use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
     // ...
 
-    class SomeCommand extends Command
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
     {
-        public function __construct(private UrlGeneratorInterface $urlGenerator)
-        {
-            parent::__construct();
+        public function __construct(
+            private UrlGeneratorInterface $urlGenerator,
+        ) {
         }
 
-        protected function execute(InputInterface $input, OutputInterface $output): int
+        public function __invoke(SymfonyStyle $io): int
         {
             // generate a URL with no route arguments
             $signUpPage = $this->urlGenerator->generate('sign_up');
@@ -2868,7 +2945,6 @@ defined as attributes:
         controllers:
             resource: '../../src/Controller/'
             type: attribute
-            defaults:
             schemes: [https]
 
     .. code-block:: xml
@@ -2943,17 +3019,88 @@ service, which you can inject in your services or controllers::
         }
     }
 
-.. versionadded:: 6.4
+For security reasons, it's common to make signed URIs expire after some time
+(e.g. when using them to reset user credentials). By default, signed URIs don't
+expire, but you can define an expiration date/time using the ``$expiration``
+argument of :method:`Symfony\\Component\\HttpFoundation\\UriSigner::sign`::
+
+    // src/Service/SomeService.php
+    namespace App\Service;
 
-    The namespace of the ``UriSigner`` class changed in Symfony 6.4 from
-    ``Symfony\Component\HttpKernel\UriSigner`` to
-    ``Symfony\Component\HttpFoundation\UriSigner``.
+    use Symfony\Component\HttpFoundation\UriSigner;
+
+    class SomeService
+    {
+        public function __construct(
+            private UriSigner $uriSigner,
+        ) {
+        }
+
+        public function someMethod(): void
+        {
+            // ...
+
+            // generate a URL yourself or get it somehow...
+            $url = 'https://example.com/foo/bar?sort=desc';
+
+            // sign the URL with an explicit expiration date
+            $signedUrl = $this->uriSigner->sign($url, new \DateTimeImmutable('2050-01-01'));
+            // $signedUrl = 'https://example.com/foo/bar?sort=desc&_expiration=2524608000&_hash=e4a21b9'
+
+            // if you pass a \DateInterval, it will be added from now to get the expiration date
+            $signedUrl = $this->uriSigner->sign($url, new \DateInterval('PT10S'));  // valid for 10 seconds from now
+            // $signedUrl = 'https://example.com/foo/bar?sort=desc&_expiration=1712414278&_hash=e4a21b9'
+
+            // you can also use a timestamp in seconds
+            $signedUrl = $this->uriSigner->sign($url, 4070908800); // timestamp for the date 2099-01-01
+            // $signedUrl = 'https://example.com/foo/bar?sort=desc&_expiration=4070908800&_hash=e4a21b9'
+        }
+    }
 
 .. note::
 
-    The generated URI hashes may include the ``/`` and ``+`` characters, which
-    can cause issues with certain clients. If you encounter this problem, replace
-    them using the following: ``strtr($hash, ['/' => '_', '+' => '-'])``.
+    The expiration date/time is included in the signed URIs as a timestamp via
+    the ``_expiration`` query parameter.
+
+.. versionadded:: 7.1
+
+    The feature to add an expiration date for a signed URI was introduced in Symfony 7.1.
+
+If you need to know the reason why a signed URI is invalid, you can use the
+``verify()`` method which throws exceptions on failure::
+
+    use Symfony\Component\HttpFoundation\Exception\ExpiredSignedUriException;
+    use Symfony\Component\HttpFoundation\Exception\UnsignedUriException;
+    use Symfony\Component\HttpFoundation\Exception\UnverifiedSignedUriException;
+
+    // ...
+
+    try {
+        $uriSigner->verify($uri); // $uri can be a string or Request object
+
+        // the URI is valid
+    } catch (UnsignedUriException) {
+        // the URI isn't signed
+    } catch (UnverifiedSignedUriException) {
+        // the URI is signed but the signature is invalid
+    } catch (ExpiredSignedUriException) {
+        // the URI is signed but expired
+    }
+
+.. versionadded:: 7.3
+
+    The ``verify()`` method was introduced in Symfony 7.3.
+
+.. tip::
+
+    If ``symfony/clock`` is installed, it will be used to create and verify
+    expirations. This allows you to :ref:`mock the current time in your tests
+    <clock_writing-tests>`.
+
+.. versionadded:: 7.3
+
+    Support for :doc:`Symfony Clock </components/clock>` in ``UriSigner`` was
+    introduced in Symfony 7.3.
 
 Troubleshooting
 ---------------
diff --git a/routing/custom_route_loader.rst b/routing/custom_route_loader.rst
index 7c76bb41e5f..b41057a81ed 100644
--- a/routing/custom_route_loader.rst
+++ b/routing/custom_route_loader.rst
@@ -108,15 +108,6 @@ Symfony provides several route loaders for the most common needs:
             $routes->import('@AcmeOtherBundle/Resources/config/routing/', 'directory');
         };
 
-.. versionadded:: 6.1
-
-    The ``attribute`` value of the second argument of ``import()`` was introduced
-    in Symfony 6.1.
-
-.. versionadded:: 6.2
-
-    The feature to import routes from a PSR-4 namespace root was introduced in Symfony 6.2.
-
 .. note::
 
     When importing resources, the key (e.g. ``app_file``) is the name of the collection.
diff --git a/scheduler.rst b/scheduler.rst
index 6701c1446e7..0d286b37d92 100644
--- a/scheduler.rst
+++ b/scheduler.rst
@@ -1,9 +1,10 @@
 Scheduler
 =========
 
-.. versionadded:: 6.3
+.. admonition:: Screencast
+    :class: screencast
 
-    The Scheduler component was introduced in Symfony 6.3
+    Like video tutorials? Check out this `Scheduler quick-start screencast`_.
 
 The scheduler component manages task scheduling within your PHP application, like
 running a task each night at 3 AM, every two weeks except for holidays or any
@@ -19,17 +20,16 @@ stack Symfony application.
 Installation
 ------------
 
-In applications using :ref:`Symfony Flex <symfony-flex>`, run this command to
-install the scheduler component:
+Run this command to install the scheduler component:
 
 .. code-block:: terminal
 
     $ composer require symfony/scheduler
 
-.. tip::
+.. note::
 
-    Starting in `MakerBundle`_ ``v1.58.0``, you can run ``php bin/console make:schedule``
-    to generate a basic schedule, that you can customize to create your own Scheduler.
+    In applications using :ref:`Symfony Flex <symfony-flex>`, installing the component
+    also creates an initial schedule that's ready to start adding your tasks.
 
 Symfony Scheduler Basics
 ------------------------
@@ -178,12 +178,6 @@ methods::
     $trigger->inner(); // CronExpressionTrigger
     $trigger->decorators(); // [ExcludeTimeTrigger, JitterTrigger]
 
-.. versionadded:: 6.4
-
-    The :method:`Symfony\\Component\\Scheduler\\Trigger\\AbstractDecoratedTrigger::inner`
-    and :method:`Symfony\\Component\\Scheduler\\Trigger\\AbstractDecoratedTrigger::decorators`
-    methods were introduced in Symfony 6.4.
-
 Most of them can be created via the :class:`Symfony\\Component\\Scheduler\\RecurringMessage`
 class, as shown in the following examples.
 
@@ -204,10 +198,6 @@ Then, define the trigger date/time using the same syntax as the
     // optionally you can define the timezone used by the cron expression
     RecurringMessage::cron('* * * * *', new Message(), new \DateTimeZone('Africa/Malabo'));
 
-.. versionadded:: 6.4
-
-    Since version 6.4, it is now possible to add and define a timezone as a 3rd argument.
-
 .. tip::
 
     Check out the `crontab.guru website`_ if you need help to construct/understand
@@ -416,10 +406,6 @@ at a defined frequency. For these dynamic scenarios, it gives you the capability
 to dynamically define our message(s) instead of statically. This is achieved by
 defining a :class:`Symfony\\Component\\Scheduler\\Trigger\\CallbackMessageProvider`.
 
-.. versionadded:: 6.4
-
-    The ``CallbackMessageProvider`` was introduced in Symfony 6.4.
-
 Essentially, this means you can dynamically, at runtime, define your message(s)
 through a callback that gets executed each time the scheduler transport
 checks for messages to be generated::
@@ -462,10 +448,10 @@ by adding one of these attributes to a service or a command:
 :class:`Symfony\\Component\\Scheduler\\Attribute\\AsCronTask`.
 
 For both of these attributes, you have the ability to define the schedule to
-use via the ``schedule``option. By default, the ``default`` named schedule will
+use via the ``schedule`` option. By default, the ``default`` named schedule will
 be used. Also, by default, the ``__invoke`` method of your service will be called
-but, it's also possible to specify the method to call via the ``method``option
-and you can define arguments via ``arguments``option if necessary.
+but, it's also possible to specify the method to call via the ``method`` option
+and you can define arguments via ``arguments`` option if necessary.
 
 .. _scheduler-attributes-cron-task:
 
@@ -502,12 +488,8 @@ The attribute takes more parameters to customize the trigger::
     // when applying this attribute to a Symfony console command, you can pass
     // arguments and options to the command using the 'arguments' option:
     #[AsCronTask('0 0 * * *', arguments: 'some_argument --some-option --another-option=some_value')]
-    class MyCommand extends Command
-
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\Scheduler\\Attribute\\AsCronTask` attribute
-    was introduced in Symfony 6.4.
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
 
 .. _scheduler-attributes-periodic-task:
 
@@ -556,12 +538,8 @@ The ``#[AsPeriodicTask]`` attribute takes many parameters to customize the trigg
     // when applying this attribute to a Symfony console command, you can pass
     // arguments and options to the command using the 'arguments' option:
     #[AsPeriodicTask(frequency: '1 day', arguments: 'some_argument --some-option --another-option=some_value')]
-    class MyCommand extends Command
-
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Component\\Scheduler\\Attribute\\AsPeriodicTask` attribute
-    was introduced in Symfony 6.4.
+    #[AsCommand(name: 'app:my-command')]
+    class MyCommand
 
 Managing Scheduled Messages
 ---------------------------
@@ -777,10 +755,15 @@ after a message is consumed::
         $schedule = $event->getSchedule();
         $context = $event->getMessageContext();
         $message = $event->getMessage();
+        $result = $event->getResult();
 
-        // do something with the schedule, context or message
+        // do something with the schedule, context, message or result
     }
 
+.. versionadded:: 7.3
+
+    The ``getResult()`` method was introduced in Symfony 7.3.
+
 Execute this command to find out which listeners are registered for this event
 and their priorities:
 
@@ -820,11 +803,6 @@ and their priorities:
 
     $ php bin/console debug:event-dispatcher "Symfony\Component\Scheduler\Event\FailureEvent"
 
-.. versionadded:: 6.4
-
-    The ``PreRunEvent``, ``PostRunEvent`` and ``FailureEvent`` events were
-    introduced in Symfony 6.4.
-
 .. _consuming-messages-running-the-worker:
 
 Consuming Messages
@@ -903,11 +881,6 @@ code::
 Modifying the Schedule at Runtime
 ---------------------------------
 
-.. versionadded:: 6.4
-
-    Support for modifying the schedule at runtime and recalculating the heap
-    was introduced in Symfony 6.4.
-
 When a recurring message is added to or removed from the schedule,
 the scheduler automatically restarts and recalculates the internal trigger heap.
 This enables dynamic control of scheduled tasks at runtime::
@@ -986,7 +959,29 @@ While this behavior may not necessarily pose a problem, there is a possibility t
 
 That's why the scheduler allows to remember the last execution date of a message
 via the ``stateful`` option (and the :doc:`Cache component </components/cache>`).
-This allows the system to retain the state of the schedule, ensuring that when a worker is restarted, it resumes from the point it left off.::
+This allows the system to retain the state of the schedule, ensuring that when a
+worker is restarted, it resumes from the point it left off::
+
+    // src/Scheduler/SaleTaskProvider.php
+    namespace App\Scheduler;
+
+    #[AsSchedule('uptoyou')]
+    class SaleTaskProvider implements ScheduleProviderInterface
+    {
+        public function getSchedule(): Schedule
+        {
+            $this->removeOldReports = RecurringMessage::cron('3 8 * * 1', new CleanUpOldSalesReport());
+
+            return $this->schedule ??= (new Schedule())
+                ->with(
+                    // ...
+                )
+                ->stateful($this->cache)
+        }
+    }
+
+With the ``stateful`` option, all missed messages will be handled. If you need to
+handle a message only once, you can use the ``processOnlyLastMissedRun`` option::
 
     // src/Scheduler/SaleTaskProvider.php
     namespace App\Scheduler;
@@ -1003,9 +998,14 @@ This allows the system to retain the state of the schedule, ensuring that when a
                     // ...
                 )
                 ->stateful($this->cache)
+                ->processOnlyLastMissedRun(true)
         }
     }
 
+.. versionadded:: 7.2
+
+    The ``processOnlyLastMissedRun`` option was introduced in Symfony 7.2.
+
 To scale your schedules more effectively, you can use multiple workers. In such
 cases, a good practice is to add a :doc:`lock </components/lock>` to prevent the
 same task more than once::
@@ -1058,14 +1058,9 @@ When using the ``RedispatchMessage``, Symfony will attach a
 :class:`Symfony\\Component\\Scheduler\\Messenger\\ScheduledStamp` to the message,
 helping you identify those messages when needed.
 
-.. versionadded:: 6.4
-
-    Automatically attaching a :class:`Symfony\\Component\\Scheduler\\Messenger\\ScheduledStamp`
-    to redispatched messages was introduced in Symfony 6.4.
-
-.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html
 .. _`Deploying to Production`: https://symfony.com/doc/current/messenger.html#deploying-to-production
 .. _`Memoizing`: https://en.wikipedia.org/wiki/Memoization
 .. _`cron command-line utility`: https://en.wikipedia.org/wiki/Cron
 .. _`crontab.guru website`: https://crontab.guru/
 .. _`relative formats`: https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative
+.. _`Scheduler quick-start screencast`: https://symfonycasts.com/screencast/mailtrap/bonus-symfony-scheduler
diff --git a/security.rst b/security.rst
index 6bf25a68b80..bc394fd95b8 100644
--- a/security.rst
+++ b/security.rst
@@ -193,14 +193,7 @@ from the `MakerBundle`_:
             return $this;
         }
 
-        /**
-         * @see UserInterface
-         */
-        public function eraseCredentials(): void
-        {
-            // If you store any temporary, sensitive data on the user, clear it here
-            // $this->plainPassword = null;
-        }
+        // [...]
     }
 
 .. tip::
@@ -449,6 +442,8 @@ the database::
     Doctrine repository class related to the user class must implement the
     :class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface`.
 
+.. _security-make-registration-form:
+
 .. tip::
 
     The ``make:registration-form`` maker command can help you set-up the
@@ -469,12 +464,6 @@ You can also manually hash a password by running:
 Read more about all available hashers and password migration in
 :doc:`security/passwords`.
 
-.. versionadded:: 6.2
-
-    In applications using Symfony 6.2 and PHP 8.2 or newer, the
-    `SensitiveParameter PHP attribute`_ is applied to all plain passwords and
-    sensitive tokens so they don't appear in stack traces.
-
 .. _firewalls-authentication:
 .. _a-authentication-firewalls:
 
@@ -626,10 +615,6 @@ don't accidentally block Symfony's dev tools - which live under URLs like
 
     This feature is not supported by the XML configuration format.
 
-    .. versionadded:: 6.4
-
-        The feature to use an array of regex was introduced in Symfony 6.4.
-
 A firewall can have many modes of authentication, in other words, it enables many
 ways to ask the question "Who are you?". Often, the user is unknown (i.e. not logged in)
 when they first visit your website. If you visit your homepage right now, you *will*
@@ -695,10 +680,6 @@ use the :class:`Symfony\\Bundle\\SecurityBundle\\Security` service::
         }
     }
 
-.. versionadded:: 6.2
-
-    The ``getFirewallConfig()`` method was introduced in Symfony 6.2.
-
 .. _security-authenticators:
 
 Authenticating Users
@@ -1749,17 +1730,6 @@ for more information about this.
 Login Programmatically
 ----------------------
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\Bundle\SecurityBundle\Security <Symfony\\Bundle\\SecurityBundle\\Security>`
-    class was introduced in Symfony 6.2. Prior to 6.2, it was called
-    ``Symfony\Component\Security\Core\Security``.
-
-.. versionadded:: 6.2
-
-    The :method:`Symfony\\Bundle\\SecurityBundle\\Security::login`
-    method was introduced in Symfony 6.2.
-
 You can log in a user programmatically using the ``login()`` method of the
 :class:`Symfony\\Bundle\\SecurityBundle\\Security` helper::
 
@@ -1789,9 +1759,12 @@ You can log in a user programmatically using the ``login()`` method of the
             // you can also log in on a different firewall...
             $security->login($user, 'form_login', 'other_firewall');
 
-            // ...and add badges
+            // ... add badges...
             $security->login($user, 'form_login', 'other_firewall', [(new RememberMeBadge())->enable()]);
 
+            // ... and also add passport attributes
+            $security->login($user, 'form_login', 'other_firewall', [(new RememberMeBadge())->enable()], ['referer' => 'https://oauth.example.com']);
+
             // use the redirection logic applied to regular login
             $redirectResponse = $security->login($user);
             return $redirectResponse;
@@ -1801,13 +1774,11 @@ You can log in a user programmatically using the ``login()`` method of the
         }
     }
 
-.. versionadded:: 6.3
-
-    The feature to use a custom redirection logic was introduced in Symfony 6.3.
-
-.. versionadded:: 6.4
+.. versionadded:: 7.2
 
-    The feature to add badges was introduced in Symfony 6.4.
+    The support for passport attributes in the
+    :method:`Symfony\\Bundle\\SecurityBundle\\Security::login` method was
+    introduced in Symfony 7.2.
 
 .. _security-logging-out:
 
@@ -1917,25 +1888,9 @@ you have imported the logout route loader in your routes:
             $routes->import('security.route_loader.logout', 'service');
         };
 
-.. versionadded:: 6.4
-
-    The :class:`Symfony\\Bundle\\SecurityBundle\\Routing\\LogoutRouteLoader` was
-    introduced in Symfony 6.4.
-
 Logout programmatically
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\Bundle\SecurityBundle\Security <Symfony\\Bundle\\SecurityBundle\\Security>`
-    class was introduced in Symfony 6.2. Prior to 6.2, it was called
-    ``Symfony\Component\Security\Core\Security``.
-
-.. versionadded:: 6.2
-
-    The :method:`Symfony\\Bundle\\SecurityBundle\\Security::logout`
-    method was introduced in Symfony 6.2.
-
 You can logout user programmatically using the ``logout()`` method of the
 :class:`Symfony\\Bundle\\SecurityBundle\\Security` helper::
 
@@ -2169,12 +2124,6 @@ If you need to get the logged in user from a service, use the
         }
     }
 
-.. versionadded:: 6.2
-
-    The :class:`Symfony\\Bundle\\SecurityBundle\\Security` class
-    was introduced in Symfony 6.2. In previous Symfony versions this class was
-    defined in ``Symfony\Component\Security\Core\Security``.
-
 Fetch the User in a Template
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2574,15 +2523,6 @@ that is thrown with the ``exceptionCode`` argument::
         // ...
     }
 
-.. versionadded:: 6.2
-
-    The ``#[IsGranted]`` attribute was introduced in Symfony 6.2.
-
-.. versionadded:: 6.3
-
-    The ``exceptionCode`` argument of the ``#[IsGranted]`` attribute was
-    introduced in Symfony 6.3.
-
 .. _security-template:
 
 Access Control in Templates
@@ -2599,6 +2539,17 @@ the built-in ``is_granted()`` helper function in any Twig template:
 
 .. _security-isgranted:
 
+Similarly, if you want to check if a specific user has a certain role, you can use
+the built-in ``is_granted_for_user()`` helper function:
+
+.. code-block:: html+twig
+
+    {% if is_granted_for_user(user, 'ROLE_ADMIN') %}
+        <a href="...">Delete</a>
+    {% endif %}
+
+.. _security-isgrantedforuser:
+
 Securing other Services
 .......................
 
@@ -2635,6 +2586,19 @@ want to include extra details only for users that have a ``ROLE_SALES_ADMIN`` ro
           // ...
       }
 
+
+.. tip::
+
+    The ``isGranted()`` method checks authorization for the currently logged-in user.
+    If you need to check authorization for a different user or when the user session
+    is unavailable (e.g., in a CLI context such as a message queue or cron job), you
+    can use the ``isGrantedForUser()`` method to explicitly set the target user.
+
+    .. versionadded:: 7.3
+
+        The :method:`Symfony\\Bundle\\SecurityBundle\\Security::isGrantedForUser`
+        method was introduced in Symfony 7.3.
+
 If you're using the :ref:`default services.yaml configuration <service-container-services-load-example>`,
 Symfony will automatically pass the ``security.helper`` to your service
 thanks to autowiring and the ``Security`` type-hint.
@@ -2730,13 +2694,14 @@ anonymous users access by checking if there is no user set on the token::
     // ...
     use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
     use Symfony\Component\Security\Core\Authentication\User\UserInterface;
+    use Symfony\Component\Security\Core\Authorization\Voter\Vote;
     use Symfony\Component\Security\Core\Authorization\Voter\Voter;
 
     class PostVoter extends Voter
     {
         // ...
 
-        protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
+        protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token, ?Vote $vote = null): bool
         {
             // ...
 
@@ -2748,6 +2713,11 @@ anonymous users access by checking if there is no user set on the token::
         }
     }
 
+.. versionadded:: 7.3
+    
+    The ``$vote`` argument of the ``voteOnAttribute()`` method was introduced
+    in Symfony 7.3.
+
 Setting Individual User Permissions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2798,15 +2768,6 @@ like this:
   :doc:`impersonating </security/impersonating_user>` another user in this
   session, this attribute will match.
 
-.. note::
-
-    All logged in users also have an attribute called ``IS_AUTHENTICATED_REMEMBERED``,
-    even if the application doesn't use the Remember Me feature. This attribute
-    exists for backward-compatibility reasons with Symfony versions prior to 6.4.
-
-    This attribute behaves the same as ``IS_AUTHENTICATED``. That's why in modern
-    Symfony applications it's recommended to no longer use ``IS_AUTHENTICATED_REMEMBERED``.
-
 .. _user_session_refresh:
 
 Understanding how Users are Refreshed from the Session
@@ -2824,7 +2785,35 @@ object) are "compared" to see if they are "equal". By default, the core
 your user will be logged out. This is a security measure to make sure that malicious
 users can be de-authenticated if core user data changes.
 
-However, in some cases, this process can cause unexpected authentication problems.
+Storing the (plain or hashed) password in the session can be a security risk.
+To mitigate this, implement the ``__serialize()`` magic method in your user class
+to exclude or transform the password before storing the serialized user object
+in the session.
+
+Two strategies are supported:
+
+#. Remove the password completely. After unserialization, ``getPassword()`` returns
+   ``null`` and Symfony refreshes the user without checking the password. Use this
+   only if you store plaintext passwords (not recommended).
+#. Hash the password using the ``crc32c`` algorithm. Symfony will hash the password
+   of the refreshed user and compare it to the session value. This approach avoids
+   storing the real hash and lets you invalidate sessions on password change.
+
+   Example (assuming the password is stored in a private property called ``password``)::
+
+       public function __serialize(): array
+       {
+           $data = (array) $this;
+           $data["\0".self::class."\0password"] = hash('crc32c', $this->password);
+
+           return $data;
+       }
+
+.. versionadded:: 7.3
+
+    Support for hashing passwords with ``crc32c`` in session serialization was
+    introduced in Symfony 7.3.
+
 If you're having problems authenticating, it could be that you *are* authenticating
 successfully, but you immediately lose authentication after the first redirect.
 
@@ -3033,5 +3022,4 @@ Authorization (Denying Access)
 .. _`HTTP Basic authentication`: https://en.wikipedia.org/wiki/Basic_access_authentication
 .. _`Login CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests
 .. _`PHP date relative formats`: https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative
-.. _`SensitiveParameter PHP attribute`: https://www.php.net/manual/en/class.sensitiveparameter.php
 .. _`Oauth2-client`: https://github.com/thephpleague/oauth2-client
diff --git a/security/access_control.rst b/security/access_control.rst
index d658b6b7c26..8e62e8a84c7 100644
--- a/security/access_control.rst
+++ b/security/access_control.rst
@@ -19,10 +19,10 @@ things:
 1. Matching Options
 -------------------
 
-Symfony creates an instance of :class:`Symfony\\Component\\HttpFoundation\\RequestMatcher`
-for each ``access_control`` entry, which determines whether or not a given
-access control should be used on this request. The following ``access_control``
-options are used for matching:
+Symfony uses :class:`Symfony\\Component\\HttpFoundation\\ChainRequestMatcher` for
+each ``access_control`` entry, which determines which implementation of
+:class:`Symfony\\Component\\HttpFoundation\\RequestMatcherInterface` should be used
+on this request. The following ``access_control`` options are used for matching:
 
 * ``path``: a regular expression (without delimiters)
 * ``ip`` or ``ips``: netmasks are also supported (can be a comma-separated string)
@@ -33,14 +33,6 @@ options are used for matching:
 * ``attributes``: an array, which can be used to specify one or more :ref:`request attributes <accessing-request-data>` that must match exactly
 * ``route``: a route name
 
-.. versionadded:: 6.1
-
-    The ``request_matcher`` option was introduced in Symfony 6.1.
-
-.. versionadded:: 6.2
-
-    The ``route`` and ``attributes`` options were introduced in Symfony 6.2.
-
 Take the following ``access_control`` entries as an example:
 
 .. configuration-block::
diff --git a/security/access_token.rst b/security/access_token.rst
index 608a8395844..70c9e21980e 100644
--- a/security/access_token.rst
+++ b/security/access_token.rst
@@ -355,10 +355,6 @@ an authorization server.
 1) Configure the OidcUserInfoTokenHandler
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    The ``OidcUserInfoTokenHandler`` class was introduced in Symfony 6.3.
-
 The ``OidcUserInfoTokenHandler`` requires the ``symfony/http-client`` package to
 make the needed HTTP requests. If you haven't installed it yet, run this command:
 
@@ -415,6 +411,76 @@ and retrieve the user info:
             ;
         };
 
+To enable `OpenID Connect Discovery`_, the ``OidcUserInfoTokenHandler``
+requires the ``symfony/cache`` package to store the OIDC configuration in
+the cache. If you haven't installed it yet, run the following command:
+
+.. code-block:: terminal
+
+    $ composer require symfony/cache
+
+Next, configure the ``base_uri`` and ``discovery`` options:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/security.yaml
+        security:
+            firewalls:
+                main:
+                    access_token:
+                        token_handler:
+                            oidc_user_info:
+                                base_uri: https://www.example.com/realms/demo/
+                                discovery:
+                                    cache: cache.app
+
+    .. code-block:: xml
+
+        <!-- config/packages/security.xml -->
+        <?xml version="1.0" encoding="UTF-8"?>
+        <srv:container xmlns="http://symfony.com/schema/dic/security"
+            xmlns:srv="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/security
+                https://symfony.com/schema/dic/security/security-1.0.xsd">
+
+            <config>
+                <firewall name="main">
+                    <access-token>
+                        <token-handler>
+                            <oidc-user-info base-uri="https://www.example.com/realms/demo/">
+                                <discovery cache="cache.app"/>
+                            </oidc-user-info>
+                        </token-handler>
+                    </access-token>
+                </firewall>
+            </config>
+        </srv:container>
+
+    .. code-block:: php
+
+        // config/packages/security.php
+        use Symfony\Config\SecurityConfig;
+
+        return static function (SecurityConfig $security) {
+            $security->firewall('main')
+                ->accessToken()
+                    ->tokenHandler()
+                        ->oidcUserInfo()
+                            ->baseUri('https://www.example.com/realms/demo/')
+                            ->discovery()
+                                ->cache('cache.app')
+            ;
+        };
+
+.. versionadded:: 7.3
+
+    Support for OpenID Connect Discovery was introduced in Symfony 7.3.
+
 Following the `OpenID Connect Specification`_, the ``sub`` claim is used as user
 identifier by default. To use another claim, specify it on the configuration:
 
@@ -542,22 +608,15 @@ claims. To create your own user object from the claims, you must
 2) Configure the OidcTokenHandler
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    The ``OidcTokenHandler`` class was introduced in Symfony 6.3.
-
-The ``OidcTokenHandler`` requires ``web-token/jwt-signature``,
-``web-token/jwt-checker`` and ``web-token/jwt-signature-algorithm-ecdsa``
-packages. If you haven't installed them yet, run these commands:
+The ``OidcTokenHandler`` requires the ``web-token/jwt-library`` package.
+If you haven't installed it yet, run this command:
 
 .. code-block:: terminal
 
-    $ composer require web-token/jwt-signature
-    $ composer require web-token/jwt-checker
-    $ composer require web-token/jwt-signature-algorithm-ecdsa
+    $ composer require web-token/jwt-library
 
-Symfony provides a generic ``OidcTokenHandler`` to decode your token, validate
-it and retrieve the user info from it:
+Symfony provides a generic ``OidcTokenHandler`` that decodes the token, validates
+it, and retrieves the user information from it. Optionally, the token can be encrypted (JWE):
 
 .. configuration-block::
 
@@ -570,14 +629,19 @@ it and retrieve the user info from it:
                     access_token:
                         token_handler:
                             oidc:
-                                # Algorithm used to sign the JWS
-                                algorithm: 'ES256'
+                                # Algorithms used to sign the JWS
+                                algorithms: ['ES256', 'RS256']
                                 # A JSON-encoded JWK
-                                key: '{"kty":"...","k":"..."}'
+                                keyset: '{"keys":[{"kty":"...","k":"..."}]}'
                                 # Audience (`aud` claim): required for validation purpose
                                 audience: 'api-example'
                                 # Issuers (`iss` claim): required for validation purpose
                                 issuers: ['https://oidc.example.com']
+                                encryption:
+                                    enabled: true # Default to false
+                                    enforce: false # Default to false, requires an encrypted token when true
+                                    algorithms: ['ECDH-ES', 'A128GCM']
+                                    keyset: '{"keys": [...]}' # Encryption private keyset
 
     .. code-block:: xml
 
@@ -598,9 +662,15 @@ it and retrieve the user info from it:
                             <!-- Algorithm used to sign the JWS -->
                             <!-- A JSON-encoded JWK -->
                             <!-- Audience (`aud` claim): required for validation purpose -->
-                            <oidc algorithm="ES256" key="{'kty':'...','k':'...'}" audience="api-example">
+                            <oidc keyset="{'keys':[{'kty':'...','k':'...'}]}" audience="api-example">
                                 <!-- Issuers (`iss` claim): required for validation purpose -->
+                                <algorithm>ES256</algorithm>
+                                <algorithm>RS256</algorithm>
                                 <issuer>https://oidc.example.com</issuer>
+                                <encryption enabled="true" enforce="true" keyset="{'keys': [...]}">
+                                    <algorithm>ECDH-ES</algorithm>
+                                    <algorithm>A128GCM</algorithm>
+                                </encryption>
                             </oidc>
                         </token-handler>
                     </access-token>
@@ -619,13 +689,108 @@ it and retrieve the user info from it:
                     ->tokenHandler()
                         ->oidc()
                             // Algorithm used to sign the JWS
-                            ->algorithm('ES256')
-                            // A JSON-encoded JWK
-                            ->key('{"kty":"...","k":"..."}')
+                            ->algorithms(['ES256', 'RS256'])
+                            // A JSON-encoded JWKSet (public keys)
+                            ->keyset('{"keys":[{"kty":"...","k":"..."}]}')
                             // Audience (`aud` claim): required for validation purpose
                             ->audience('api-example')
                             // Issuers (`iss` claim): required for validation purpose
                             ->issuers(['https://oidc.example.com'])
+                            ->encryption()
+                                ->enabled(true) //Default to false
+                                ->enforce(false) //Default to false, requires an encrypted token when true
+                                // Algorithm used to decrypt the JWE
+                                ->algorithms(['ECDH-ES', 'A128GCM'])
+                                // A JSON-encoded JWKSet (private keys)
+                                ->keyset('{"keys":[...]}')
+
+            ;
+        };
+
+.. versionadded:: 7.1
+
+    The support of multiple algorithms to sign the JWS was introduced in Symfony 7.1.
+    In previous versions, only the ``ES256`` algorithm was supported.
+
+.. versionadded:: 7.3
+
+    Support for encryption algorithms to decrypt JWEs was introduced in Symfony 7.3.
+
+To enable `OpenID Connect Discovery`_, the ``OidcTokenHandler`` requires the
+``symfony/cache`` package to store the OIDC configuration in the cache. If you
+haven't installed it yet, run the following command:
+
+.. code-block:: terminal
+
+    $ composer require symfony/cache
+
+Then, you can remove the ``keyset`` configuration option (it will be imported
+from the OpenID Connect Discovery), and configure the ``discovery`` option:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/security.yaml
+        security:
+            firewalls:
+                main:
+                    access_token:
+                        token_handler:
+                            oidc:
+                                claim: email
+                                algorithms: ['ES256', 'RS256']
+                                audience: 'api-example'
+                                issuers: ['https://oidc.example.com']
+                                discovery:
+                                    base_uri: https://www.example.com/realms/demo/
+                                    cache: cache.app
+
+    .. code-block:: xml
+
+        <!-- config/packages/security.xml -->
+        <?xml version="1.0" encoding="UTF-8"?>
+        <srv:container xmlns="http://symfony.com/schema/dic/security"
+            xmlns:srv="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/security
+                https://symfony.com/schema/dic/security/security-1.0.xsd">
+
+            <config>
+                <firewall name="main">
+                    <access-token>
+                        <token-handler>
+                            <oidc claim="email" audience="api-example">
+                                <algorithm>ES256</algorithm>
+                                <algorithm>RS256</algorithm>
+                                <issuer>https://oidc.example.com</issuer>
+                                <discovery base-uri="https://www.example.com/realms/demo/" cache="cache.app">
+                            </oidc>
+                        </token-handler>
+                    </access-token>
+                </firewall>
+            </config>
+        </srv:container>
+
+    .. code-block:: php
+
+        // config/packages/security.php
+        use Symfony\Config\SecurityConfig;
+
+        return static function (SecurityConfig $security) {
+            $security->firewall('main')
+                ->accessToken()
+                    ->tokenHandler()
+                        ->oidc()
+                            ->claim('email')
+                            ->algorithms(['ES256', 'RS256'])
+                            ->audience('api-example')
+                            ->issuers(['https://oidc.example.com'])
+                            ->discovery()
+                                ->baseUri('https://www.example.com/realms/demo/')
+                                ->cache('cache.app')
             ;
         };
 
@@ -645,8 +810,8 @@ configuration:
                         token_handler:
                             oidc:
                                 claim: email
-                                algorithm: 'ES256'
-                                key: '{"kty":"...","k":"..."}'
+                                algorithms: ['ES256', 'RS256']
+                                keyset: '{"keys":[{"kty":"...","k":"..."}]}'
                                 audience: 'api-example'
                                 issuers: ['https://oidc.example.com']
 
@@ -666,7 +831,9 @@ configuration:
                 <firewall name="main">
                     <access-token>
                         <token-handler>
-                            <oidc claim="email" algorithm="ES256" key="{'kty':'...','k':'...'}" audience="api-example">
+                            <oidc claim="email" keyset="{'keys':[{'kty':'...','k':'...'}]}" audience="api-example">
+                                <algorithm>ES256</algorithm>
+                                <algorithm>RS256</algorithm>
                                 <issuer>https://oidc.example.com</issuer>
                             </oidc>
                         </token-handler>
@@ -686,8 +853,8 @@ configuration:
                     ->tokenHandler()
                         ->oidc()
                             ->claim('email')
-                            ->algorithm('ES256')
-                            ->key('{"kty":"...","k":"..."}')
+                            ->algorithms(['ES256', 'RS256'])
+                            ->keyset('{"keys":[{"kty":"...","k":"..."}]}')
                             ->audience('api-example')
                             ->issuers(['https://oidc.example.com'])
             ;
@@ -708,13 +875,193 @@ create your own User from the claims, you must
         }
     }
 
-Creating Users from Token
--------------------------
+Using CAS 2.0
+-------------
+
+.. versionadded:: 7.1
+
+    The support for CAS token handlers was introduced in Symfony 7.1.
+
+`Central Authentication Service (CAS)`_ is an enterprise multilingual single
+sign-on solution and identity provider for the web and attempts to be a
+comprehensive platform for your authentication and authorization needs.
 
-.. versionadded:: 6.3
+Configure the Cas2Handler
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    The possibility to omit the user provider in case of stateless firewalls
-    was introduced in Symfony 6.3.
+Symfony provides a generic ``Cas2Handler`` to call your CAS server. It requires
+the ``symfony/http-client`` package to make the needed HTTP requests. If you
+haven't installed it yet, run this command:
+
+.. code-block:: terminal
+
+    $ composer require symfony/http-client
+
+You can configure a ``cas`` token handler as follows:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/security.yaml
+        security:
+            firewalls:
+                main:
+                    access_token:
+                        token_handler:
+                            cas:
+                                validation_url: https://www.example.com/cas/validate
+
+    .. code-block:: xml
+
+        <!-- config/packages/security.xml -->
+        <?xml version="1.0" encoding="UTF-8"?>
+        <srv:container xmlns="http://symfony.com/schema/dic/security"
+            xmlns:srv="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/security
+                https://symfony.com/schema/dic/security/security-1.0.xsd">
+
+            <config>
+                <firewall name="main">
+                    <access-token>
+                        <token-handler>
+                            <cas validation-url="https://www.example.com/cas/validate"/>
+                        </token-handler>
+                    </access-token>
+                </firewall>
+            </config>
+        </srv:container>
+
+    .. code-block:: php
+
+        // config/packages/security.php
+        use Symfony\Config\SecurityConfig;
+
+        return static function (SecurityConfig $security) {
+            $security->firewall('main')
+                ->accessToken()
+                    ->tokenHandler()
+                        ->cas()
+                            ->validationUrl('https://www.example.com/cas/validate')
+            ;
+        };
+
+The ``cas`` token handler automatically creates an HTTP client to call
+the specified ``validation_url``. If you prefer using your own client, you can
+specify the service name via the ``http_client`` option:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/security.yaml
+        security:
+            firewalls:
+                main:
+                    access_token:
+                        token_handler:
+                            cas:
+                                validation_url: https://www.example.com/cas/validate
+                                http_client: cas.client
+
+    .. code-block:: xml
+
+        <!-- config/packages/security.xml -->
+        <?xml version="1.0" encoding="UTF-8"?>
+        <srv:container xmlns="http://symfony.com/schema/dic/security"
+            xmlns:srv="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/security
+                https://symfony.com/schema/dic/security/security-1.0.xsd">
+
+            <config>
+                <firewall name="main">
+                    <access-token>
+                        <token-handler>
+                            <cas validation-url="https://www.example.com/cas/validate" http-client="cas.client"/>
+                        </token-handler>
+                    </access-token>
+                </firewall>
+            </config>
+        </srv:container>
+
+    .. code-block:: php
+
+        // config/packages/security.php
+        use Symfony\Config\SecurityConfig;
+
+        return static function (SecurityConfig $security) {
+            $security->firewall('main')
+                ->accessToken()
+                    ->tokenHandler()
+                        ->cas()
+                            ->validationUrl('https://www.example.com/cas/validate')
+                            ->httpClient('cas.client')
+            ;
+        };
+
+By default the token handler will read the validation URL XML response with
+ ``cas`` prefix but you can configure another prefix:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/security.yaml
+        security:
+            firewalls:
+                main:
+                    access_token:
+                        token_handler:
+                            cas:
+                                validation_url: https://www.example.com/cas/validate
+                                prefix: cas-example
+
+    .. code-block:: xml
+
+        <!-- config/packages/security.xml -->
+        <?xml version="1.0" encoding="UTF-8"?>
+        <srv:container xmlns="http://symfony.com/schema/dic/security"
+            xmlns:srv="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/security
+                https://symfony.com/schema/dic/security/security-1.0.xsd">
+
+            <config>
+                <firewall name="main">
+                    <access-token>
+                        <token-handler>
+                            <cas validation-url="https://www.example.com/cas/validate" prefix="cas-example"/>
+                        </token-handler>
+                    </access-token>
+                </firewall>
+            </config>
+        </srv:container>
+
+    .. code-block:: php
+
+        // config/packages/security.php
+        use Symfony\Config\SecurityConfig;
+
+        return static function (SecurityConfig $security) {
+            $security->firewall('main')
+                ->accessToken()
+                    ->tokenHandler()
+                        ->cas()
+                            ->validationUrl('https://www.example.com/cas/validate')
+                            ->prefix('cas-example')
+            ;
+        };
+
+Creating Users from Token
+-------------------------
 
 Some types of tokens (for instance OIDC) contain all information required
 to create a user entity (e.g. username and roles). In this case, you don't
@@ -743,8 +1090,10 @@ need a user provider to create a user from the database::
 When using this strategy, you can omit the ``user_provider`` configuration
 for :ref:`stateless firewalls <reference-security-stateless>`.
 
+.. _`Central Authentication Service (CAS)`: https://en.wikipedia.org/wiki/Central_Authentication_Service
 .. _`JSON Web Tokens (JWT)`: https://datatracker.ietf.org/doc/html/rfc7519
-.. _`SAML2 (XML structures)`: https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html
-.. _`RFC6750`: https://datatracker.ietf.org/doc/html/rfc6750
-.. _`OpenID Connect Specification`: https://openid.net/specs/openid-connect-core-1_0.html
 .. _`OpenID Connect (OIDC)`: https://en.wikipedia.org/wiki/OpenID#OpenID_Connect_(OIDC)
+.. _`OpenID Connect Specification`: https://openid.net/specs/openid-connect-core-1_0.html
+.. _`OpenID Connect Discovery`: https://openid.net/specs/openid-connect-discovery-1_0.html
+.. _`RFC6750`: https://datatracker.ietf.org/doc/html/rfc6750
+.. _`SAML2 (XML structures)`: https://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-tech-overview-2.0.html
diff --git a/security/csrf.rst b/security/csrf.rst
index 2902ab27d61..8797b4e7553 100644
--- a/security/csrf.rst
+++ b/security/csrf.rst
@@ -34,6 +34,10 @@ unique tokens added to forms as hidden fields. The legit server validates them t
 ensure that the request originated from the expected source and not some other
 malicious website.
 
+Anti-CSRF tokens can be managed in two ways: using a **stateful** approach,
+where tokens are stored in the session and are unique per user and action; or a
+**stateless** approach, where tokens are generated on the client side.
+
 Installation
 ------------
 
@@ -85,14 +89,14 @@ for more information):
             ;
         };
 
-The tokens used for CSRF protection are meant to be different for every user and
-they are stored in the session. That's why a session is started automatically as
-soon as you render a form with CSRF protection.
+By default, the tokens used for CSRF protection are stored in the session.
+That's why a session is started automatically as soon as you render a form
+with CSRF protection.
 
 .. _caching-pages-that-contain-csrf-protected-forms:
 
-Moreover, this means that you cannot fully cache pages that include CSRF
-protected forms. As an alternative, you can:
+This leads to many strategies to help with caching pages that include CSRF
+protected forms, among them:
 
 * Embed the form inside an uncached :doc:`ESI fragment </http_cache/esi>` and
   cache the rest of the page contents;
@@ -101,6 +105,9 @@ protected forms. As an alternative, you can:
   load the CSRF token with an uncached AJAX request and replace the form
   field value with it.
 
+The most effective way to cache pages that need CSRF protected forms is to use
+:ref:`stateless CSRF tokens <csrf-stateless-tokens>`, as explained below.
+
 .. _csrf-protection-forms:
 
 CSRF Protection in Symfony Forms
@@ -183,6 +190,7 @@ method of each form::
                 'csrf_field_name' => '_token',
                 // an arbitrary string used to generate the value of the token
                 // using a different string for each form improves its security
+                // when using stateful tokens (which is the default)
                 'csrf_token_id'   => 'task_item',
             ]);
         }
@@ -190,7 +198,7 @@ method of each form::
         // ...
     }
 
-You can also customize the rendering of the CSRF form field creating a custom
+You can also customize the rendering of the CSRF form field by creating a custom
 :doc:`form theme </form/form_themes>` and using ``csrf_token`` as the prefix of
 the field (e.g. define ``{% block csrf_token_widget %} ... {% endblock %}`` to
 customize the entire form field contents).
@@ -221,7 +229,7 @@ generate a CSRF token in the template and store it as a hidden form field:
 .. code-block:: html+twig
 
     <form action="{{ url('admin_post_delete', { id: post.id }) }}" method="post">
-        {# the argument of csrf_token() is an arbitrary string used to generate the token #}
+        {# the argument of csrf_token() is the ID of this token #}
         <input type="hidden" name="token" value="{{ csrf_token('delete-item') }}">
 
         <button type="submit">Delete item</button>
@@ -229,7 +237,7 @@ generate a CSRF token in the template and store it as a hidden form field:
 
 Then, get the value of the CSRF token in the controller action and use the
 :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::isCsrfTokenValid`
-method to check its validity::
+method to check its validity, passing the same token ID used in the template::
 
     use Symfony\Component\HttpFoundation\Request;
     use Symfony\Component\HttpFoundation\Response;
@@ -245,6 +253,83 @@ method to check its validity::
         }
     }
 
+.. _csrf-controller-attributes:
+
+Alternatively you can use the
+:class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid`
+attribute on the controller action::
+
+    use Symfony\Component\HttpFoundation\Request;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
+    // ...
+
+    #[IsCsrfTokenValid('delete-item', tokenKey: 'token')]
+    public function delete(): Response
+    {
+        // ... do something, like deleting an object
+    }
+
+Suppose you want a CSRF token per item, so in the template you have something like the following:
+
+.. code-block:: html+twig
+
+    <form action="{{ url('admin_post_delete', { id: post.id }) }}" method="post">
+        {# the argument of csrf_token() is a dynamic id string used to generate the token #}
+        <input type="hidden" name="token" value="{{ csrf_token('delete-item-' ~ post.id) }}">
+
+        <button type="submit">Delete item</button>
+    </form>
+
+This attribute can also be applied to a controller class. When used this way,
+the CSRF token validation will be applied to **all actions** defined in that
+controller::
+
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
+    // ...
+
+    #[IsCsrfTokenValid('the token ID')]
+    final class SomeController extends AbstractController
+    {
+        // ...
+    }
+
+The :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid`
+attribute also accepts an :class:`Symfony\\Component\\ExpressionLanguage\\Expression`
+object evaluated to the id::
+
+    use Symfony\Component\HttpFoundation\Request;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
+    // ...
+
+    #[IsCsrfTokenValid(new Expression('"delete-item-" ~ args["post"].getId()'), tokenKey: 'token')]
+    public function delete(Post $post): Response
+    {
+        // ... do something, like deleting an object
+    }
+
+By default, the ``IsCsrfTokenValid`` attribute performs the CSRF token check for
+all HTTP methods. You can restrict this validation to specific methods using the
+``methods`` parameter. If the request uses a method not listed in the ``methods``
+array, the attribute is ignored for that request, and no CSRF validation occurs::
+
+    #[IsCsrfTokenValid('delete-item', tokenKey: 'token', methods: ['DELETE'])]
+    public function delete(Post $post): Response
+    {
+        // ... delete the object
+    }
+
+.. versionadded:: 7.1
+
+    The :class:`Symfony\\Component\\Security\\Http\\Attribute\\IsCsrfTokenValid`
+    attribute was introduced in Symfony 7.1.
+
+.. versionadded:: 7.3
+
+    The ``methods`` parameter was introduced in Symfony 7.3.
+
 CSRF Tokens and Compression Side-Channel Attacks
 ------------------------------------------------
 
@@ -254,6 +339,171 @@ targeted parts of the plaintext. To mitigate these attacks, and prevent an
 attacker from guessing the CSRF tokens, a random mask is prepended to the token
 and used to scramble it.
 
+.. _csrf-stateless-tokens:
+
+Stateless CSRF Tokens
+---------------------
+
+.. versionadded:: 7.2
+
+    Stateless anti-CSRF protection was introduced in Symfony 7.2.
+
+Traditionally, CSRF tokens are stateful, meaning they're stored in the session.
+However, some token IDs can be declared as stateless using the
+``stateless_token_ids`` option. Stateless CSRF tokens are enabled by default
+in applications using :ref:`Symfony Flex <symfony-flex>`.
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/csrf.yaml
+        framework:
+            # ...
+            csrf_protection:
+                stateless_token_ids: ['submit', 'authenticate', 'logout']
+
+    .. code-block:: xml
+
+        <!-- config/packages/csrf.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony
+                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:csrf-protection>
+                    <framework:stateless-token-id>submit</framework:stateless-token-id>
+                    <framework:stateless-token-id>authenticate</framework:stateless-token-id>
+                    <framework:stateless-token-id>logout</framework:stateless-token-id>
+                </framework:csrf-protection>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/csrf.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->csrfProtection()
+                ->statelessTokenIds(['submit', 'authenticate', 'logout'])
+            ;
+        };
+
+Stateless CSRF tokens provide protection without relying on the session. This
+allows you to fully cache pages while still protecting against CSRF attacks.
+
+When validating a stateless CSRF token, Symfony checks the ``Origin`` and
+``Referer`` headers of the incoming HTTP request. If either header matches the
+application's target origin (i.e. its domain), the token is considered valid.
+
+This mechanism relies on the application being able to determine its own origin.
+If you're behind a reverse proxy, make sure it's properly configured. See
+:doc:`/deployment/proxies`.
+
+Using a Default Token ID
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Stateful CSRF tokens are typically scoped per form or action, while stateless
+tokens don't require many identifiers.
+
+In the example above, the ``authenticate`` and ``logout`` identifiers are listed
+because they are used by default in the Symfony Security component. The ``submit``
+identifier is included so that form types defined by the application can also use
+CSRF protection by default.
+
+The following configuration applies only to form types registered via
+:ref:`autoconfiguration <services-autoconfigure>` (which is the default for your
+own services), and it sets ``submit`` as their default token identifier:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/csrf.yaml
+        framework:
+            form:
+                csrf_protection:
+                    token_id: 'submit'
+
+    .. code-block:: xml
+
+        <!-- config/packages/csrf.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony
+                https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:form>
+                    <framework:csrf-protection token-id="submit"/>
+                </framework:form>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/csrf.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->form()
+                ->csrfProtection()
+                    ->tokenId('submit')
+            ;
+        };
+
+Forms configured with a token identifier listed in the above ``stateless_token_ids``
+option will use the stateless CSRF protection.
+
+Generating CSRF Token Using Javascript
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In addition to the ``Origin`` and ``Referer`` HTTP headers, stateless CSRF protection
+can also validate tokens using a cookie and a header (named ``csrf-token`` by
+default; see the :ref:`CSRF configuration reference <reference-framework-csrf-protection>`).
+
+These additional checks are part of the **defense-in-depth** strategy provided by
+stateless CSRF protection. They are optional and require `some JavaScript`_ to
+be enabled. This JavaScript generates a cryptographically secure random token
+when a form is submitted. It then inserts the token into the form's hidden CSRF
+field and sends it in both a cookie and a request header.
+
+On the server side, CSRF token validation compares the values in the cookie and
+the header. This "double-submit" protection relies on the browser's same-origin
+policy and is further hardened by:
+
+* generating a new token for each submission (to prevent cookie fixation);
+* using ``samesite=strict`` and ``__Host-`` cookie attributes (to enforce HTTPS
+  and limit the cookie to the current domain).
+
+By default, the Symfony JavaScript snippet expects the hidden CSRF field to be
+named ``_csrf_token`` or to include the ``data-controller="csrf-protection"``
+attribute. You can adapt this logic to your needs as long as the same protocol
+is followed.
+
+To prevent validation from being downgraded, an extra behavioral check is performed:
+if (and only if) a session already exists, successful "double-submit" is remembered
+and becomes required for future requests. This ensures that once the optional cookie/header
+validation has been proven effective, it remains enforced for that session.
+
+.. note::
+
+    Enforcing "double-submit" validation on all requests is not recommended,
+    as it may lead to a broken user experience. The opportunistic approach
+    described above is preferred, allowing the application to gracefully
+    fall back to ``Origin`` / ``Referer`` checks when JavaScript is unavailable.
+
 .. _`Cross-site request forgery`: https://en.wikipedia.org/wiki/Cross-site_request_forgery
 .. _`BREACH`: https://en.wikipedia.org/wiki/BREACH
 .. _`CRIME`: https://en.wikipedia.org/wiki/CRIME
+.. _`some JavaScript`: https://github.com/symfony/recipes/blob/main/symfony/stimulus-bundle/2.20/assets/controllers/csrf_protection_controller.js
diff --git a/security/custom_authenticator.rst b/security/custom_authenticator.rst
index 365d4bd8f1d..462ec21521c 100644
--- a/security/custom_authenticator.rst
+++ b/security/custom_authenticator.rst
@@ -130,7 +130,7 @@ should review it:
                 http://symfony.com/schema/dic/security
                 https://symfony.com/schema/dic/security/security-1.0.xsd">
 
-            <config enable-authenticator-manager="true">
+            <config>
                 <!-- ... -->
 
                 <firewall name="main">
@@ -229,13 +229,20 @@ requires a user and some sort of "credentials" (e.g. a password).
 Use the
 :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Badge\\UserBadge`
 to attach the user to the passport. The ``UserBadge`` requires a user
-identifier (e.g. the username or email), which is used to load the user
-using :ref:`the user provider <security-user-providers>`::
+identifier (e.g. the username or email)::
 
     use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
 
     // ...
-    $passport = new Passport(new UserBadge($email), $credentials);
+    $passport = new Passport(new UserBadge($userIdentifier), $credentials);
+
+User Identifier
+~~~~~~~~~~~~~~~
+
+The user identifier is a unique string that identifies the user. It is often
+something like their email address or username, but it can be any unique value
+associated with the user. It allows loading the user through the configured
+:ref:`user provider <security-user-providers>`.
 
 .. note::
 
@@ -275,6 +282,69 @@ using :ref:`the user provider <security-user-providers>`::
             }
         }
 
+Some applications normalize user identifiers before processing them. For example,
+lowercasing identifiers helps treat values like "john.doe", "John.Doe", or
+"JOHN.DOE" as equivalent in systems where identifiers are case-insensitive.
+
+If needed, you can pass a normalizer as the third argument to ``UserBadge``.
+This callable receives the ``$userIdentifier`` and must return a string.
+
+.. versionadded:: 7.3
+
+    Support for user identifier normalizers was introduced in Symfony 7.3.
+
+The example below uses a normalizer that converts usernames to a normalized,
+ASCII-only, lowercase format::
+
+    // src/Security/NormalizedUserBadge.php
+    namespace App\Security;
+
+    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
+    use function Symfony\Component\String\u;
+
+    final class NormalizedUserBadge extends UserBadge
+    {
+        public function __construct(string $identifier)
+        {
+            $callback = static fn (string $identifier): string => u($identifier)->normalize(UnicodeString::NFKC)->ascii()->lower()->toString();
+
+            parent::__construct($identifier, null, $callback);
+        }
+    }
+
+::
+
+    // src/Security/PasswordAuthenticator.php
+    namespace App\Security;
+
+    final class PasswordAuthenticator extends AbstractLoginFormAuthenticator
+    {
+        // simplified for brevity
+        public function authenticate(Request $request): Passport
+        {
+            $username = (string) $request->request->get('username', '');
+            $password = (string) $request->request->get('password', '');
+
+            $request->getSession()
+                ->set(SecurityRequestAttributes::LAST_USERNAME, $username);
+
+            return new Passport(
+                new NormalizedUserBadge($username),
+                new PasswordCredentials($password),
+                [
+                    // all other useful badges
+                ]
+            );
+        }
+    }
+
+User Credential
+~~~~~~~~~~~~~~~
+
+The user credential is used to authenticate the user; that is, to verify
+the validity of the provided information (such as a password, an API token,
+or custom credentials).
+
 The following credential classes are supported by default:
 
 :class:`Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Credentials\\PasswordCredentials`
diff --git a/security/entry_point.rst b/security/entry_point.rst
index 666acac427c..cfbef00ff88 100644
--- a/security/entry_point.rst
+++ b/security/entry_point.rst
@@ -42,7 +42,7 @@ You can configure this using the ``entry_point`` setting:
                 http://symfony.com/schema/dic/security
                 https://symfony.com/schema/dic/security/security-1.0.xsd">
 
-            <config enable-authenticator-manager="true">
+            <config>
                 <!-- ... -->
 
                 <!-- entry-point: configure the form authentication as the entry
diff --git a/security/expressions.rst b/security/expressions.rst
index fcf87269bc5..a4ec02c7b84 100644
--- a/security/expressions.rst
+++ b/security/expressions.rst
@@ -69,10 +69,6 @@ and ``#[IsGranted]`` attribute also accept an
             }
         }
 
-.. versionadded:: 6.2
-
-    The ``#[IsGranted]`` attribute was introduced in Symfony 6.2.
-
 In this example, if the current user has ``ROLE_ADMIN`` or if the current
 user object's ``isSuperAdmin()`` method returns ``true``, then access will
 be granted (note: your User object may not have an ``isSuperAdmin()`` method,
@@ -205,6 +201,38 @@ Inside the subject's expression, you have access to two variables:
 ``args``
     An array of controller arguments that are passed to the controller.
 
+Additionally to expressions, the ``#[IsGranted]`` attribute also accepts
+closures that return a boolean value. The subject can also be a closure that
+returns an array of values that will be injected into the closure::
+
+    // src/Controller/MyController.php
+    namespace App\Controller;
+
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\HttpFoundation\Response;
+    use Symfony\Component\Security\Http\Attribute\IsGranted;
+    use Symfony\Component\Security\Http\Attribute\IsGrantedContext;
+
+    class MyController extends AbstractController
+    {
+        #[IsGranted(static function (IsGrantedContext $context, mixed $subject) {
+            return $context->user === $subject['post']->getAuthor();
+        }, subject: static function (array $args) {
+            return [
+                'post' => $args['post'],
+            ];
+        })]
+        public function index($post): Response
+        {
+            // ...
+        }
+    }
+
+.. versionadded:: 7.3
+
+    The support for closures in the ``#[IsGranted]`` attribute was introduced
+    in Symfony 7.3 and requires PHP 8.5.
+
 Learn more
 ----------
 
diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst
index a641d62612e..6f22e7aace6 100644
--- a/security/impersonating_user.rst
+++ b/security/impersonating_user.rst
@@ -74,10 +74,6 @@ as the value to the current URL:
 
     You can leverage the Twig function ``impersonation_path('thomas')``
 
-    .. versionadded:: 6.4
-
-        The ``impersonation_path()`` function was introduced in Symfony 6.4.
-
 .. tip::
 
     Instead of adding a ``_switch_user`` query string parameter, you can pass
@@ -254,10 +250,6 @@ also adjust the query parameter name via the ``parameter`` setting:
 Redirecting to a Specific Target Route
 --------------------------------------
 
-.. versionadded:: 6.2
-
-    The ``target_route`` configuration option was introduced in Symfony 6.2.
-
 .. note::
 
     It works only in a stateful firewall.
diff --git a/security/ldap.rst b/security/ldap.rst
index 4345f55e6d9..c4c3646122b 100644
--- a/security/ldap.rst
+++ b/security/ldap.rst
@@ -256,6 +256,24 @@ This is the default role you wish to give to a user fetched from the LDAP
 server. If you do not configure this key, your users won't have any roles,
 and will not be considered as authenticated fully.
 
+role_fetcher
+............
+
+**Type**: ``string`` **Default**: ``null``
+
+When your LDAP service provides user roles, this option allows you to define
+the service that retrieves these roles. The role fetcher service must implement
+the ``Symfony\Component\Ldap\Security\RoleFetcherInterface``. When this option
+is set, the ``default_roles`` option is ignored.
+
+Symfony provides ``Symfony\Component\Ldap\Security\MemberOfRoles``, a concrete
+implementation of the interface that fetches roles from the ``ismemberof``
+attribute.
+
+.. versionadded:: 7.3
+
+    The ``role_fetcher`` configuration option was introduced in Symfony 7.3.
+
 uid_key
 .......
 
@@ -289,11 +307,6 @@ string will be replaced by the value of the ``uid_key`` configuration value
 (by default, ``sAMAccountName``), and the ``{user_identifier}`` string will be
 replaced by the user identified you are trying to load.
 
-.. deprecated:: 6.2
-
-    Starting from Symfony 6.2, the ``{username}`` string was deprecated in favor
-    of ``{user_identifier}``.
-
 For example, with a ``uid_key`` of ``uid``, and if you are trying to
 load the user ``fabpot``, the final string will be: ``(uid=fabpot)``.
 
diff --git a/security/login_link.rst b/security/login_link.rst
index 4ee1773d4e0..57d353278c2 100644
--- a/security/login_link.rst
+++ b/security/login_link.rst
@@ -808,7 +808,3 @@ but you can change the lifetime per link using the third argument of the
     // the third optional argument is the lifetime in seconds
     $loginLinkDetails = $loginLinkHandler->createLoginLink($user, null, 60);
     $loginLink = $loginLinkDetails->getUrl();
-
-.. versionadded:: 6.2
-
-    The argument to customize the link lifetime was introduced in Symfony 6.2.
diff --git a/security/remember_me.rst b/security/remember_me.rst
index b4d2b5ae14d..2fd0f7e8d1e 100644
--- a/security/remember_me.rst
+++ b/security/remember_me.rst
@@ -19,7 +19,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option:
                 main:
                     # ...
                     remember_me:
-                        secret:   '%kernel.secret%' # required
+                        secret: '%kernel.secret%'
                         lifetime: 604800 # 1 week in seconds
                         # by default, the feature is enabled by checking a
                         # checkbox in the login form (see below), uncomment the
@@ -44,7 +44,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option:
                 <firewall name="main">
                     <!-- ... -->
 
-                    <!-- secret: required
+                    <!-- secret: default to "%kernel.secret%"
                          lifetime: 604800 is 1 week in seconds -->
                     <remember-me
                         secret="%kernel.secret%"
@@ -67,7 +67,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option:
             $security->firewall('main')
                 // ...
                 ->rememberMe()
-                    ->secret('%kernel.secret%') // required
+                    ->secret('%kernel.secret%')
                     ->lifetime(604800) // 1 week in seconds
 
                     // by default, the feature is enabled by checking a
@@ -77,9 +77,11 @@ the session lasts using a cookie with the ``remember_me`` firewall option:
             ;
         };
 
-The ``secret`` option is the only required option and it is used to sign
-the remember me cookie. It's common to use the ``kernel.secret`` parameter,
-which is defined using the ``APP_SECRET`` environment variable.
+.. versionadded:: 7.2
+
+    The ``secret`` option is no longer required starting from Symfony 7.2. By
+    default, ``%kernel.secret%`` is used, which is defined using the
+    ``APP_SECRET`` environment variable.
 
 After enabling the ``remember_me`` system in the configuration, there are a
 couple more things to do before remember me works correctly:
@@ -152,10 +154,6 @@ you can add a ``_remember_me`` key to the body of your POST request.
     Optionally, you can configure a custom name for this key using the
     ``name`` setting under the ``remember_me`` section of your firewall.
 
-.. versionadded:: 6.3
-
-    The JSON login ``_remember_me`` option was introduced in Symfony 6.3.
-
 Always activating Remember Me
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -175,7 +173,6 @@ allow users to opt-out. In these cases, you can use the
                 main:
                     # ...
                     remember_me:
-                        secret: '%kernel.secret%'
                         # ...
                         always_remember_me: true
 
@@ -198,7 +195,6 @@ allow users to opt-out. In these cases, you can use the
                     <!-- ... -->
 
                     <remember-me
-                        secret="%kernel.secret%"
                         always-remember-me="true"
                     />
                 </firewall>
@@ -215,7 +211,6 @@ allow users to opt-out. In these cases, you can use the
             $security->firewall('main')
                 // ...
                 ->rememberMe()
-                    ->secret('%kernel.secret%')
                     // ...
                     ->alwaysRememberMe(true)
             ;
@@ -339,7 +334,6 @@ are fetched from the user object using the
                 main:
                     # ...
                     remember_me:
-                        secret: '%kernel.secret%'
                         # ...
                         signature_properties: ['password', 'updatedAt']
 
@@ -361,7 +355,7 @@ are fetched from the user object using the
                 <firewall name="main">
                     <!-- ... -->
 
-                    <remember-me secret="%kernel.secret%">
+                    <remember-me>
                         <signature-property>password</signature-property>
                         <signature-property>updatedAt</signature-property>
                     </remember-me>
@@ -379,7 +373,6 @@ are fetched from the user object using the
             $security->firewall('main')
                 // ...
                 ->rememberMe()
-                    ->secret('%kernel.secret%')
                     // ...
                     ->signatureProperties(['password', 'updatedAt'])
             ;
@@ -423,7 +416,6 @@ You can enable the doctrine token provider using the ``doctrine`` setting:
                 main:
                     # ...
                     remember_me:
-                        secret: '%kernel.secret%'
                         # ...
                         token_provider:
                             doctrine: true
@@ -446,7 +438,7 @@ You can enable the doctrine token provider using the ``doctrine`` setting:
                 <firewall name="main">
                     <!-- ... -->
 
-                    <remember-me secret="%kernel.secret%">
+                    <remember-me>
                         <token-provider doctrine="true"/>
                     </remember-me>
                 </firewall>
@@ -463,7 +455,6 @@ You can enable the doctrine token provider using the ``doctrine`` setting:
             $security->firewall('main')
                 // ...
                 ->rememberMe()
-                    ->secret('%kernel.secret%')
                     // ...
                     ->tokenProvider([
                         'doctrine' => true,
diff --git a/security/user_checkers.rst b/security/user_checkers.rst
index 99cdfe04076..ec8f49da522 100644
--- a/security/user_checkers.rst
+++ b/security/user_checkers.rst
@@ -21,6 +21,8 @@ displayed to the user::
     namespace App\Security;
 
     use App\Entity\User as AppUser;
+    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
     use Symfony\Component\Security\Core\Exception\AccountExpiredException;
     use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException;
     use Symfony\Component\Security\Core\User\UserCheckerInterface;
@@ -40,7 +42,7 @@ displayed to the user::
             }
         }
 
-        public function checkPostAuth(UserInterface $user): void
+        public function checkPostAuth(UserInterface $user, TokenInterface $token): void
         {
             if (!$user instanceof AppUser) {
                 return;
@@ -50,9 +52,17 @@ displayed to the user::
             if ($user->isExpired()) {
                 throw new AccountExpiredException('...');
             }
+
+            if (!\in_array('foo', $token->getRoleNames())) {
+                throw new AccessDeniedException('...');
+            }
         }
     }
 
+.. versionadded:: 7.2
+
+    The ``token`` argument for the ``checkPostAuth()`` method was introduced in Symfony 7.2.
+
 Enabling the Custom User Checker
 --------------------------------
 
@@ -117,10 +127,6 @@ is the service id of your user checker:
 Using Multiple User Checkers
 ----------------------------
 
-.. versionadded:: 6.2
-
-    The ``ChainUserChecker`` class was added in Symfony 6.2.
-
 It is common for applications to have multiple authentication entry points (such as
 traditional form based login and an API) which may have unique checker rules for each
 entry point as well as common rules for all entry points. To allow using multiple user
diff --git a/security/voters.rst b/security/voters.rst
index 8959e0bf3cd..e621263abb4 100644
--- a/security/voters.rst
+++ b/security/voters.rst
@@ -40,14 +40,20 @@ or extend :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\Vote
 which makes creating a voter even easier::
 
     use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+    use Symfony\Component\Security\Core\Authorization\Voter\Vote;
     use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
 
     abstract class Voter implements VoterInterface
     {
         abstract protected function supports(string $attribute, mixed $subject): bool;
-        abstract protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool;
+        abstract protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool;
     }
 
+.. versionadded:: 7.3
+    
+    The ``$vote`` argument of the ``voteOnAttribute()`` method was introduced
+    in Symfony 7.3.
+
 .. _how-to-use-the-voter-in-a-controller:
 
 Setup: Checking for Access in a Controller
@@ -118,10 +124,6 @@ calls out to the "voter" system. Right now, no voters will vote on whether or no
 the user can "view" or "edit" a ``Post``. But you can create your *own* voter that
 decides this using whatever logic you want.
 
-.. versionadded:: 6.2
-
-    The ``#[IsGranted]`` attribute was introduced in Symfony 6.2.
-
 Creating the custom Voter
 -------------------------
 
@@ -136,6 +138,7 @@ would look like this::
     use App\Entity\Post;
     use App\Entity\User;
     use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+    use Symfony\Component\Security\Core\Authorization\Voter\Vote;
     use Symfony\Component\Security\Core\Authorization\Voter\Voter;
 
     class PostVoter extends Voter
@@ -159,12 +162,13 @@ would look like this::
             return true;
         }
 
-        protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
+        protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
         {
             $user = $token->getUser();
 
             if (!$user instanceof User) {
                 // the user must be logged in; if not, deny access
+                $vote?->addReason('The user is not logged in.');
                 return false;
             }
 
@@ -174,7 +178,7 @@ would look like this::
 
             return match($attribute) {
                 self::VIEW => $this->canView($post, $user),
-                self::EDIT => $this->canEdit($post, $user),
+                self::EDIT => $this->canEdit($post, $user, $vote),
                 default => throw new \LogicException('This code should not be reached!')
             };
         }
@@ -190,10 +194,19 @@ would look like this::
             return !$post->isPrivate();
         }
 
-        private function canEdit(Post $post, User $user): bool
+        private function canEdit(Post $post, User $user, ?Vote $vote): bool
         {
-            // this assumes that the Post object has a `getOwner()` method
-            return $user === $post->getOwner();
+            // this assumes that the Post object has a `getAuthor()` method
+            if ($user === $post->getAuthor()) {
+                return true;
+            }
+
+            $vote?->addReason(sprintf(
+                'The logged in user (username: %s) is not the author of this post (id: %d).',
+                $user->getUsername(), $post->getId()
+            ));
+
+            return false;
         }
     }
 
@@ -211,11 +224,12 @@ To recap, here's what's expected from the two abstract methods:
     return ``true`` if the attribute is ``view`` or ``edit`` and if the object is
     a ``Post`` instance.
 
-``voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token)``
+``voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null)``
     If you return ``true`` from ``supports()``, then this method is called. Your
     job is to return ``true`` to allow access and ``false`` to deny access.
-    The ``$token`` can be used to find the current user object (if any). In this
-    example, all of the complex business logic is included to determine access.
+    The ``$token`` can be used to find the current user object (if any).
+    The ``$vote`` argument can be used to provide an explanation for the vote.
+    This explanation is included in log messages and on exception pages.
 
 .. _declaring-the-voter-as-a-service:
 
@@ -252,7 +266,7 @@ with ``ROLE_SUPER_ADMIN``::
         ) {
         }
 
-        protected function voteOnAttribute($attribute, mixed $subject, TokenInterface $token): bool
+        protected function voteOnAttribute($attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
         {
             // ...
 
diff --git a/serializer.rst b/serializer.rst
index 86b0257248e..eb06f1b34a1 100644
--- a/serializer.rst
+++ b/serializer.rst
@@ -386,10 +386,6 @@ properties with a ``null`` value only for one serialize call::
 Using Context Builders
 """"""""""""""""""""""
 
-.. versionadded:: 6.1
-
-    Context builders were introduced in Symfony 6.1.
-
 You can use "context builders" to help define the (de)serialization
 context. Context builders are PHP objects that provide autocompletion,
 validation, and documentation of context options::
@@ -633,6 +629,35 @@ all the properties of the class::
         // ...
     }
 
+Serializing JSON Using Streams
+------------------------------
+
+Symfony can encode PHP data structures to JSON streams and decode JSON streams
+back into PHP data structures.
+
+To do this, it relies on the :doc:`JsonStreamer component </serializer/streaming_json>`,
+which is designed for high efficiency and can process large JSON data incrementally,
+without needing to load the entire content into memory.
+
+When deciding between the Serializer component and the JsonStreamer component,
+consider the following:
+
+* **Serializer Component**: Best suited for use cases that require flexibility,
+  such as dynamically manipulating object structures using normalizers and
+  denormalizers, or handling complex objects with multiple serialization
+  formats. It also supports output formats beyond JSON (including your own
+  custom ones).
+* **JsonStreamer Component**: Best suited for simple objects and scenarios that
+  demand high performance and low memory usage. It's particularly effective
+  for processing very large JSON datasets or when streaming JSON in real-time
+  without loading the entire dataset into memory.
+
+The choice depends on your specific use case. The JsonStreamer component is
+tailored for performance and memory efficiency, whereas the Serializer
+component provides greater flexibility and broader format support.
+
+Read more about :doc:`streaming JSON </serializer/streaming_json>`.
+
 Serializing to or from PHP Arrays
 ---------------------------------
 
@@ -1000,10 +1025,6 @@ For nested classes, you have to add a PHPDoc type to the property, constructor o
 Deserializing Nested Structures
 -------------------------------
 
-.. versionadded:: 6.2
-
-    The option to configure a ``SerializedPath`` was introduced in Symfony 6.2.
-
 Some APIs might provide verbose nested structures that you want to flatten
 in the PHP object. For instance, imagine a JSON response like this:
 
@@ -1247,6 +1268,71 @@ setting the ``name_converter`` setting to
         ];
         $serializer = new Serializer($normalizers, $encoders);
 
+snake_case to CamelCase
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In Symfony applications, it is common to use camelCase for naming properties.
+However some packages may follow a snake_case convention.
+
+Symfony provides a built-in name converter designed to transform between
+CamelCase and snake_case styles during serialization and deserialization
+processes. You can use it instead of the metadata-aware name converter by
+setting the ``name_converter`` setting to
+``serializer.name_converter.snake_case_to_camel_case``:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/serializer.yaml
+        framework:
+            serializer:
+                name_converter: 'serializer.name_converter.snake_case_to_camel_case'
+
+    .. code-block:: xml
+
+        <!-- config/packages/serializer.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:serializer
+                    name-converter="serializer.name_converter.snake_case_to_camel_case"
+                />
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/serializer.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->serializer()
+                ->nameConverter('serializer.name_converter.snake_case_to_camel_case')
+            ;
+        };
+
+    .. code-block:: php-standalone
+
+        use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter;
+        use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
+
+        // ...
+        $normalizers = [
+            new ObjectNormalizer(null, new SnakeCaseToCamelCaseNameConverter()),
+        ];
+        $serializer = new Serializer($normalizers, $encoders);
+
+.. versionadded:: 7.2
+
+    The snake_case to CamelCase converter was introduced in Symfony 7.2.
+
 .. _serializer-built-in-normalizers:
 
 Serializer Normalizers
@@ -1279,11 +1365,21 @@ normalizers (in order of priority):
 
 :class:`Symfony\\Component\\Serializer\\Normalizer\\DateTimeNormalizer`
     This normalizes between :phpclass:`DateTimeInterface` objects (e.g.
-    :phpclass:`DateTime` and :phpclass:`DateTimeImmutable`) and strings.
+    :phpclass:`DateTime` and :phpclass:`DateTimeImmutable`) and strings,
+    integers or floats.
+
+    :phpclass:`DateTime` and :phpclass:`DateTimeImmutable`) into strings,
+    integers or floats. By default, it converts them to strings using the
+    `RFC 3339`_ format. Use ``DateTimeNormalizer::FORMAT_KEY`` and
+    ``DateTimeNormalizer::TIMEZONE_KEY`` to change the format.
+
+    To convert the objects to integers or floats, set the serializer
+    context option ``DateTimeNormalizer::CAST_KEY`` to ``int`` or
+    ``float``.
 
-    By default, the `RFC 3339`_ format is used when normalizing the value.
-    Use ``DateTimeNormalizer::FORMAT_KEY`` and ``DateTimeNormalizer::TIMEZONE_KEY``
-    to change the format.
+    .. versionadded:: 7.1
+
+        The ``DateTimeNormalizer::CAST_KEY`` context option was introduced in Symfony 7.1.
 
 :class:`Symfony\\Component\\Serializer\\Normalizer\\ConstraintViolationListNormalizer`
     This normalizer converts objects that implement
@@ -1313,12 +1409,6 @@ normalizers (in order of priority):
     You can define the locale to use to translate the object by setting the
     ``TranslatableNormalizer::NORMALIZATION_LOCALE_KEY`` context option.
 
-    .. versionadded:: 6.4
-
-        The ``UidNormalizer`` normalization formats were introduced in Symfony 5.3.
-        The :class:`Symfony\\Component\\Serializer\\Normalizer\\TranslatableNormalizer`
-        was introduced in Symfony 6.4.
-
 :class:`Symfony\\Component\\Serializer\\Normalizer\\BackedEnumNormalizer`
     This normalizer converts between :phpclass:`BackedEnum` enums and
     strings or integers.
@@ -1326,9 +1416,13 @@ normalizers (in order of priority):
     By default, an exception is thrown when data is not a valid backed enumeration. If you
     want ``null`` instead, you can set the ``BackedEnumNormalizer::ALLOW_INVALID_VALUES`` option.
 
-    .. versionadded:: 6.3
+:class:`Symfony\\Component\\Serializer\\Normalizer\\NumberNormalizer`
+    This normalizer converts between :phpclass:`BcMath\\Number` or :phpclass:`GMP` objects and
+    strings or integers.
+
+.. versionadded:: 7.2
 
-        The ``BackedEnumNormalizer::ALLOW_INVALID_VALUES`` context option was introduced in Symfony 6.3.
+    The ``NumberNormalizer`` was introduced in Symfony 7.2.
 
 :class:`Symfony\\Component\\Serializer\\Normalizer\\DataUriNormalizer`
     This normalizer converts between :phpclass:`SplFileInfo` objects and a
@@ -1502,17 +1596,256 @@ like:
             PropertyNormalizer::NORMALIZE_VISIBILITY => PropertyNormalizer::NORMALIZE_PUBLIC | PropertyNormalizer::NORMALIZE_PROTECTED,
         ]);
 
-    .. versionadded:: 6.2
+Named Serializers
+-----------------
 
-        The ``PropertyNormalizer::NORMALIZE_VISIBILITY`` context option and its
-        values were introduced in Symfony 6.2.
+.. versionadded:: 7.2
 
-Debugging the Serializer
-------------------------
+    Named serializers were introduced in Symfony 7.2.
+
+Sometimes, you may need multiple configurations for the serializer, such as
+different default contexts, name converters, or sets of normalizers and encoders,
+depending on the use case. For example, when your application communicates with
+multiple APIs, each of which follows its own set of serialization rules.
+
+You can achieve this by configuring multiple serializer instances using
+the ``named_serializers`` option:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/serializer.yaml
+        framework:
+            serializer:
+                named_serializers:
+                    api_client1:
+                        name_converter: 'serializer.name_converter.camel_case_to_snake_case'
+                        default_context:
+                            enable_max_depth: true
+                    api_client2:
+                        default_context:
+                            enable_max_depth: false
+
+    .. code-block:: xml
+
+        <!-- config/packages/serializer.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+            <framework:config>
+                <framework:serializer>
+
+                    <framework:named-serializer
+                        name="api_client1"
+                        name-converter="serializer.name_converter.camel_case_to_snake_case"
+                    >
+                        <framework:default-context>
+                            <framework:enable_max_depth>true</framework:enable_max_depth>
+                        </framework:default-context>
+                    </framework:named-serializer>
+
+                    <framework:named-serializer name="api_client2">
+                        <framework:default-context>
+                            <framework:enable_max_depth>false</framework:enable_max_depth>
+                        </framework:default-context>
+                    </framework:named-serializer>
+
+                </framework:serializer>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/serializer.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->serializer()
+                ->namedSerializer('api_client1')
+                    ->nameConverter('serializer.name_converter.camel_case_to_snake_case')
+                    ->defaultContext([
+                        'enable_max_depth' => true,
+                    ])
+            ;
+            $framework->serializer()
+                ->namedSerializer('api_client2')
+                    ->defaultContext([
+                        'enable_max_depth' => false,
+                    ])
+            ;
+        };
+
+You can inject these different serializer instances
+using :ref:`named aliases <autowiring-multiple-implementations-same-type>`::
+
+    namespace App\Controller;
+
+    // ...
+    use Symfony\Component\DependencyInjection\Attribute\Target;
+
+    class PersonController extends AbstractController
+    {
+        public function index(
+            SerializerInterface $serializer,           // default serializer
+            SerializerInterface $apiClient1Serializer, // api_client1 serializer
+            #[Target('apiClient2.serializer')]         // api_client2 serializer
+            SerializerInterface $customName,
+        ) {
+            // ...
+        }
+    }
+
+By default, named serializers use the built-in set of normalizers and encoders,
+just like the main serializer service. However, you can customize them by
+registering additional normalizers or encoders for a specific named serializer.
+To do that, add a ``serializer`` attribute to
+the :ref:`serializer.normalizer <reference-dic-tags-serializer-normalizer>`
+or :ref:`serializer.encoder <reference-dic-tags-serializer-encoder>` tags:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/services.yaml
+        services:
+            # ...
+
+            Symfony\Component\Serializer\Normalizer\CustomNormalizer:
+                # prevent this normalizer from being automatically added to the default serializer
+                autoconfigure: false
+                tags:
+                    # add this normalizer only to a specific named serializer
+                    - serializer.normalizer: { serializer: 'api_client1' }
+                    # add this normalizer to several named serializers
+                    - serializer.normalizer: { serializer: [ 'api_client1', 'api_client2' ] }
+                    # add this normalizer to all serializers, including the default one
+                    - serializer.normalizer: { serializer: '*' }
+
+    .. code-block:: xml
+
+        <!-- config/services.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd">
+
+            <services>
+                <!-- ... -->
+
+                <!-- prevent this normalizer from being automatically added to the default serializer -->
+                <service
+                    id="Symfony\Component\Serializer\Normalizer\CustomNormalizer"
+                    autoconfigure="false"
+                >
+                    <!-- add this normalizer only to a specific named serializer -->
+                    <tag name="serializer.normalizer" serializer="api_client1"/>
+
+                    <!-- add this normalizer to several named serializers -->
+                    <tag name="serializer.normalizer" serializer="api_client1"/>
+                    <tag name="serializer.normalizer" serializer="api_client2"/>
+
+                    <!-- add this normalizer to all serializers, including the default one -->
+                    <tag name="serializer.normalizer" serializer="*"/>
+                </service>
+            </services>
+        </container>
+
+    .. code-block:: php
+
+        // config/services.php
+        namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+        use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
+
+        return function(ContainerConfigurator $container) {
+            // ...
+
+            $services->set(CustomNormalizer::class)
+                // prevent this normalizer from being automatically added to the default serializer
+                ->autoconfigure(false)
+
+                // add this normalizer only to a specific named serializer
+                ->tag('serializer.normalizer', ['serializer' => 'api_client1'])
+                // add this normalizer to several named serializers
+                ->tag('serializer.normalizer', ['serializer' => ['api_client1', 'api_client2']])
+                // add this normalizer to all serializers, including the default one
+                ->tag('serializer.normalizer', ['serializer' => '*'])
+            ;
+        };
+
+When the ``serializer`` attribute is not set, the service is registered only with
+the default serializer.
+
+Each normalizer or encoder used in a named serializer is tagged with a
+``serializer.normalizer.<name>`` or ``serializer.encoder.<name>`` tag.
+You can inspect their priorities using the following command:
+
+.. code-block:: terminal
+
+    $ php bin/console debug:container --tag serializer.<normalizer|encoder>.<name>
+
+Additionally, you can exclude the default set of normalizers and encoders from a
+named serializer by setting the ``include_built_in_normalizers`` and
+``include_built_in_encoders`` options to ``false``:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/serializer.yaml
+        framework:
+            serializer:
+                named_serializers:
+                    api_client1:
+                        include_built_in_normalizers: false
+                        include_built_in_encoders: true
+
+    .. code-block:: xml
+
+        <!-- config/packages/serializer.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services
+                https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
-.. versionadded:: 6.3
+            <framework:config>
+                <framework:serializer>
+
+                    <framework:named-serializer
+                        name="api_client1"
+                        include-built-in-normalizers="false"
+                        include-built-in-encoders="true"
+                    />
+
+                </framework:serializer>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/serializer.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $framework->serializer()
+                ->namedSerializer('api_client1')
+                    ->includeBuiltInNormalizers(false)
+                    ->includeBuiltInEncoders(true)
+            ;
+        };
 
-    The ``debug:serializer`` command was introduced in Symfony 6.3.
+Debugging the Serializer
+------------------------
 
 Use the ``debug:serializer`` command to dump the serializer metadata of a
 given class:
@@ -1531,20 +1864,22 @@ given class:
         |          |   "groups" => [                                            |
         |          |       "book:read",                                         |
         |          |       "book:write",                                        |
-        |          |   ]                                                        |
+        |          |   ],                                                       |
         |          |   "maxDepth" => 1,                                         |
-        |          |   "serializedName" => "book_name"                          |
-        |          |   "ignore" => false                                        |
+        |          |   "serializedName" => "book_name",                         |
+        |          |   "serializedPath" => null,                                |
+        |          |   "ignore" => false,                                       |
         |          |   "normalizationContexts" => [],                           |
         |          |   "denormalizationContexts" => []                          |
         |          | ]                                                          |
         | isbn     | [                                                          |
         |          |   "groups" => [                                            |
         |          |       "book:read",                                         |
-        |          |   ]                                                        |
+        |          |   ],                                                       |
         |          |   "maxDepth" => null,                                      |
-        |          |   "serializedName" => null                                 |
-        |          |   "ignore" => false                                        |
+        |          |   "serializedName" => null,                                |
+        |          |   "serializedPath" => "[data][isbn]",                      |
+        |          |   "ignore" => false,                                       |
         |          |   "normalizationContexts" => [],                           |
         |          |   "denormalizationContexts" => []                          |
         |          | ]                                                          |
@@ -1857,11 +2192,6 @@ Advanced Deserialization
 Require all Properties
 ~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.3
-
-    The ``AbstractNormalizer::PREVENT_NULLABLE_FALLBACK`` context option
-    was introduced in Symfony 6.3.
-
 By default, the Serializer will add ``null`` to nullable properties when
 the parameters for those are not provided. You can change this behavior by
 setting the ``AbstractNormalizer::REQUIRE_ALL_PROPERTIES`` context option
@@ -2083,6 +2413,70 @@ correct class for properties typed as ``InvoiceItemInterface``::
         $invoiceLine = $serializer->deserialize($jsonString, InvoiceLine::class, 'json');
         // $invoiceLine contains new InvoiceLine(new Product(...))
 
+You can add a default type to avoid the need to add the type property
+when deserializing:
+
+.. configuration-block::
+
+    .. code-block:: php-attributes
+
+        namespace App\Model;
+
+        use Symfony\Component\Serializer\Attribute\DiscriminatorMap;
+
+        #[DiscriminatorMap(
+            typeProperty: 'type',
+            mapping: [
+                'product' => Product::class,
+                'shipping' => Shipping::class,
+            ],
+            defaultType: 'product',
+        )]
+        interface InvoiceItemInterface
+        {
+            // ...
+        }
+
+    .. code-block:: yaml
+
+        App\Model\InvoiceItemInterface:
+            discriminator_map:
+                type_property: type
+                mapping:
+                    product: 'App\Model\Product'
+                    shipping: 'App\Model\Shipping'
+                default_type: product
+
+    .. code-block:: xml
+
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping
+                https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
+        >
+            <class name="App\Model\InvoiceItemInterface">
+                <discriminator-map type-property="type" default-type="product">
+                    <mapping type="product" class="App\Model\Product"/>
+                    <mapping type="shipping" class="App\Model\Shipping"/>
+                </discriminator-map>
+            </class>
+        </serializer>
+
+Now it deserializes like this:
+
+.. configuration-block::
+
+    .. code-block:: php
+
+        // $jsonString does NOT contain "type" in "invoiceItem"
+        $invoiceLine = $serializer->deserialize('{"invoiceItem":{...},...}', InvoiceLine::class, 'json');
+        // $invoiceLine contains new InvoiceLine(new Product(...))
+
+.. versionadded:: 7.3
+
+    The ``defaultType`` parameter was added in Symfony 7.3.
+
 .. _serializer-unwrapping-denormalizer:
 
 Deserializing Input Partially (Unwrapping)
@@ -2141,6 +2535,32 @@ will be thrown. The type enforcement of the properties can be disabled by
 setting the serializer context option
 ``ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT`` to ``true``.
 
+Handling Boolean Values
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 7.1
+
+    The ``AbstractNormalizer::FILTER_BOOL`` context option was introduced in Symfony 7.1.
+
+PHP considers many different values as true or false. For example, the
+strings ``true``, ``1``, and ``yes`` are considered true, while
+``false``, ``0``, and ``no`` are considered false.
+
+When deserializing, the Serializer component can take care of this
+automatically. This can be done by using the ``AbstractNormalizer::FILTER_BOOL``
+context option::
+
+    use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
+    // ...
+
+    $person = $serializer->denormalize(['sportsperson' => 'yes'], Person::class, context: [
+        AbstractNormalizer::FILTER_BOOL => true
+    ]);
+    // $person contains a Person instance with sportsperson set to true
+
+This context makes the deserialization process behave like the
+:phpfunction:`filter_var` function with the ``FILTER_VALIDATE_BOOL`` flag.
+
 .. _serializer-enabling-metadata-cache:
 
 Configuring the Metadata Cache
diff --git a/serializer/custom_context_builders.rst b/serializer/custom_context_builders.rst
index 9d7b925480e..e25b6d77813 100644
--- a/serializer/custom_context_builders.rst
+++ b/serializer/custom_context_builders.rst
@@ -1,10 +1,6 @@
 How to Create your Custom Context Builder
 =========================================
 
-.. versionadded:: 6.1
-
-    Context builders were introduced in Symfony 6.1.
-
 That serialization process of the :doc:`Serializer Component </serializer>`
 can be configured by the :ref:`serialization context <serializer-context>`,
 which can be built thanks to :ref:`context builders <serializer-using-context-builders>`.
diff --git a/serializer/custom_name_converter.rst b/serializer/custom_name_converter.rst
index 82247134217..49dafb02cc4 100644
--- a/serializer/custom_name_converter.rst
+++ b/serializer/custom_name_converter.rst
@@ -30,19 +30,26 @@ A custom name converter can handle such cases::
 
     class OrgPrefixNameConverter implements NameConverterInterface
     {
-        public function normalize(string $propertyName): string
+        public function normalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string
         {
             // during normalization, add the prefix
             return 'org_'.$propertyName;
         }
 
-        public function denormalize(string $propertyName): string
+        public function denormalize(string $propertyName, ?string $class = null, ?string $format = null, array $context = []): string
         {
             // remove the 'org_' prefix on denormalizing
             return str_starts_with($propertyName, 'org_') ? substr($propertyName, 4) : $propertyName;
         }
     }
 
+.. versionadded:: 7.1
+
+    Accessing the current class name, format and context via
+    :method:`Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::normalize`
+    and :method:`Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::denormalize`
+    was introduced in Symfony 7.1.
+
 .. note::
 
     You can also implement
diff --git a/serializer/custom_normalizer.rst b/serializer/custom_normalizer.rst
index d965c62e2ef..4e78d9d394e 100644
--- a/serializer/custom_normalizer.rst
+++ b/serializer/custom_normalizer.rst
@@ -13,52 +13,53 @@ Creating a New Normalizer
 Imagine you want add, modify, or remove some properties during the serialization
 process. For that you'll have to create your own normalizer. But it's usually
 preferable to let Symfony normalize the object, then hook into the normalization
-to customize the normalized data. To do that, leverage the ``ObjectNormalizer``::
+to customize the normalized data. To do that, you can inject a
+``NormalizerInterface`` and wire it to Symfony's object normalizer. This will give
+you access to a ``$normalizer`` property which takes care of most of the
+normalization process::
 
     // src/Serializer/TopicNormalizer.php
     namespace App\Serializer;
 
     use App\Entity\Topic;
+    use Symfony\Component\DependencyInjection\Attribute\Autowire;
     use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-    use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
-    use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
     use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
-    use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
 
     class TopicNormalizer implements NormalizerInterface
     {
         public function __construct(
+            #[Autowire(service: 'serializer.normalizer.object')]
+            private readonly NormalizerInterface $normalizer,
+
             private UrlGeneratorInterface $router,
-            private ObjectNormalizer $normalizer,
         ) {
         }
 
-        public function normalize(mixed $object, ?string $format = null, array $context = []): array
+        public function normalize(mixed $data, ?string $format = null, array $context = []): array
         {
-            $data = $this->normalizer->normalize($object, $format, $context);
+            $normalizedData = $this->normalizer->normalize($data, $format, $context);
 
             // Here, add, edit, or delete some data:
-            $data['href']['self'] = $this->router->generate('topic_show', [
-                'id' => $object->getId(),
+            $normalizedData['href']['self'] = $this->router->generate('topic_show', [
+                'id' => $data->getId(),
             ], UrlGeneratorInterface::ABSOLUTE_URL);
 
-            return $data;
+            return $normalizedData;
         }
 
         public function supportsNormalization($data, ?string $format = null, array $context = []): bool
         {
             return $data instanceof Topic;
         }
-    }
-
-.. deprecated:: 6.1
 
-    Injecting an ``ObjectNormalizer`` in your custom normalizer is deprecated
-    since Symfony 6.1. Implement the
-    :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizerAwareInterface`
-    and use the
-    :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizerAwareTrait` instead
-    to inject the ``$normalizer`` property.
+        public function getSupportedTypes(?string $format): array
+        {
+            return [
+                Topic::class => true,
+            ];
+        }
+    }
 
 Registering it in your Application
 ----------------------------------
@@ -125,44 +126,8 @@ If you're not using ``autoconfigure``, you have to tag the service with
             ;
         };
 
-Performance
------------
-
-To figure which normalizer (or denormalizer) must be used to handle an object,
-the :class:`Symfony\\Component\\Serializer\\Serializer` class will call the
-:method:`Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface::supportsNormalization`
-(or :method:`Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface::supportsDenormalization`)
-of all registered normalizers (or denormalizers) in a loop.
-
-The result of these methods can vary depending on the object to serialize, the
-format and the context. That's why the result **is not cached** by default and
-can result in a significant performance bottleneck.
-
-However, most normalizers (and denormalizers) always return the same result when
-the object's type and the format are the same, so the result can be cached. To
-do so, make those normalizers (and denormalizers) implement the
-:class:`Symfony\\Component\\Serializer\\Normalizer\\CacheableSupportsMethodInterface`
-and return ``true`` when
-:method:`Symfony\\Component\\Serializer\\Normalizer\\CacheableSupportsMethodInterface::hasCacheableSupportsMethod`
-is called.
-
-.. note::
-
-    All built-in :ref:`normalizers and denormalizers <serializer-built-in-normalizers>`
-    as well the ones included in `API Platform`_ natively implement this interface.
-
-.. deprecated:: 6.3
-
-    The :class:`Symfony\\Component\\Serializer\\Normalizer\\CacheableSupportsMethodInterface`
-    interface is deprecated since Symfony 6.3. You should implement the
-    ``getSupportedTypes()`` method instead, as shown in the section below.
-
 Improving Performance of Normalizers/Denormalizers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. versionadded:: 6.3
-
-    The ``getSupportedTypes()`` method was introduced in Symfony 6.3.
+--------------------------------------------------
 
 Both :class:Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface
 and :class:Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface
@@ -210,5 +175,3 @@ Here is an example of how to use the ``getSupportedTypes()`` method::
 
     The ``supports*()`` method implementations should not assume that
     ``getSupportedTypes()`` has been called before.
-
-.. _`API Platform`: https://api-platform.com
diff --git a/serializer/encoders.rst b/serializer/encoders.rst
index 4a83522c2fb..8238d4d057d 100644
--- a/serializer/encoders.rst
+++ b/serializer/encoders.rst
@@ -45,10 +45,6 @@ All context options available for the JSON encoder are:
     If set to ``true`` returns the result as an array, returns a nested ``stdClass`` hierarchy otherwise.
 ``json_decode_detailed_errors`` (default: ``false``)
     If set to ``true`` exceptions thrown on parsing of JSON are more specific. Requires `seld/jsonlint`_ package.
-
-    .. versionadded:: 6.4
-
-        The ``json_decode_detailed_errors`` option was introduced in Symfony 6.4.
 ``json_decode_options`` (default: ``0``)
     Flags passed to :phpfunction:`json_decode` function.
 ``json_encode_options`` (default: ``\JSON_PRESERVE_ZERO_FRACTION``)
@@ -69,6 +65,11 @@ are available to customize the behavior of the encoder:
 ``csv_end_of_line`` (default: ``\n``)
     Sets the character(s) used to mark the end of each line in the CSV file.
 ``csv_escape_char`` (default: empty string)
+
+    .. deprecated:: 7.2
+
+        The ``csv_escape_char`` option was deprecated in Symfony 7.2.
+
     Sets the escape character (at most one character).
 ``csv_key_separator`` (default: ``.``)
     Sets the separator for array's keys during its flattening
@@ -195,20 +196,25 @@ These are the options available on the :ref:`serializer context <serializer-cont
     XML loading `options with libxml`_.
 ``save_options`` (default: ``0``)
     XML saving `options with libxml`_.
-
-    .. versionadded:: 6.3
-
-        The ``save_options`` option was introduced in Symfony 6.3.
 ``remove_empty_tags`` (default: ``false``)
     If set to ``true``, removes all empty tags in the generated XML.
 ``cdata_wrapping`` (default: ``true``)
     If set to ``false``, will not wrap any value containing one of the
     following characters ( ``<``, ``>``, ``&``) in `a CDATA section`_ like
     following: ``<![CDATA[...]]>``.
+``cdata_wrapping_pattern`` (default: ``/[<>&]/``)
+    A regular expression pattern to determine if a value should be wrapped
+    in a CDATA section.
+``ignore_empty_attributes`` (default: ``false``)
+    If set to true, ignores all attributes with empty values in the generated XML
+
+.. versionadded:: 7.1
+
+    The ``cdata_wrapping_pattern`` option was introduced in Symfony 7.1.
 
-    .. versionadded:: 6.4
+.. versionadded:: 7.3
 
-        The ``cdata_wrapping`` option was introduced in Symfony 6.4.
+    The ``ignore_empty_attributes`` option was introduced in Symfony 7.3.
 
 Example with a custom ``context``::
 
diff --git a/serializer/streaming_json.rst b/serializer/streaming_json.rst
new file mode 100644
index 00000000000..3fd44824bc6
--- /dev/null
+++ b/serializer/streaming_json.rst
@@ -0,0 +1,664 @@
+Streaming JSON
+==============
+
+.. versionadded:: 7.3
+
+    The JsonStreamer component was introduced in Symfony 7.3 as an
+    :doc:`experimental feature </contributing/code/experimental>`.
+
+Symfony can encode PHP data structures to JSON streams and decode JSON streams
+back into PHP data structures.
+
+To do so, it relies on the **JsonStreamer** component, which is designed for
+high efficiency and can process large JSON data incrementally without needing
+to load the entire content into memory.
+
+This component is ideal for handling APIs or interacting with third-party APIs.
+It transforms incoming JSON request payloads into PHP objects that your
+application can work with. Similarly, it converts processed PHP objects into a
+JSON stream for outgoing responses.
+
+Installation
+------------
+
+In applications using :ref:`Symfony Flex <symfony-flex>`, run this command to
+install the JsonStreamer component:
+
+.. code-block:: terminal
+
+    $ composer require symfony/json-streamer
+
+.. include:: /components/require_autoload.rst.inc
+
+Encoding Objects
+----------------
+
+JsonStreamer only works with PHP classes that have **no constructor** and are
+composed solely of **public properties**, like `DTO classes`_. Consider the
+following ``Cat`` class::
+
+    // src/Dto/Cat.php
+    namespace App\Dto;
+
+    class Cat
+    {
+        public string $name;
+        public string $age;
+    }
+
+To encode ``Cat`` objects into a JSON stream (e.g., to send them in an API
+response), first apply the ``#[JsonStreamable]`` attribute to the class. This
+attribute is optional, but it :ref:`improves performance <json-streamer-streamable-attribute>`
+by pre-generating encoding and decoding files during cache warm-up::
+
+    namespace App\Dto;
+
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+
+    #[JsonStreamable]
+    class Cat
+    {
+        // ...
+    }
+
+Next, inject the JSON stream writer into your service. The service ``id`` is
+``json_streamer.stream_writer``, but you can also get it by type-hinting a
+``$jsonStreamWriter`` argument with :class:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface`.
+
+Use the :method:`Symfony\\Component\\JsonStreamer\\StreamWriterInterface::write`
+method of the service to perform the actual JSON conversion:
+
+.. configuration-block::
+
+    .. code-block:: php-symfony
+
+        // src/Controller/CatController.php
+        namespace App\Controller;
+
+        use App\Dto\Cat;
+        use App\Repository\CatRepository;
+        use Symfony\Component\HttpFoundation\StreamedResponse;
+        use Symfony\Component\JsonStreamer\StreamWriterInterface;
+        use Symfony\Component\TypeInfo\Type;
+
+        class CatController
+        {
+            public function retrieveCats(StreamWriterInterface $jsonStreamWriter, CatRepository $catRepository): StreamedResponse
+            {
+                $cats = $catRepository->findAll();
+                $type = Type::list(Type::object(Cat::class));
+
+                $json = $jsonStreamWriter->write($cats, $type);
+
+                return new StreamedResponse($json);
+            }
+        }
+
+    .. code-block:: php-standalone
+
+        use App\Dto\Cat;
+        use App\Repository\CatRepository;
+        use Symfony\Component\HttpFoundation\StreamedResponse;
+        use Symfony\Component\JsonStreamer\JsonStreamWriter;
+        use Symfony\Component\TypeInfo\Type;
+
+        // ...
+
+        $jsonWriter = JsonStreamWriter::create();
+
+        $cats = $catRepository->findAll();
+        $type = Type::list(Type::object(Cat::class));
+
+        $json = $jsonWriter->write($cats, $type);
+
+        $response = new StreamedResponse($json);
+
+        // ...
+
+.. tip::
+
+    You can explicitly inject the ``json_streamer.stream_writer`` service by
+    using the ``#[Target('json_streamer.stream_writer')]`` autowire attribute.
+
+Decoding Objects
+----------------
+
+In addition to encoding, you can decode JSON into PHP objects.
+
+To do this, inject the JSON stream reader into your service. The service ``id`` is
+``json_streamer.stream_reader``, but you can also get it by type-hinting a
+``$jsonStreamReader`` argument with :class:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface`.
+Next, use the :method:`Symfony\\Component\\JsonStreamer\\StreamReaderInterface::read`
+method to perform the actual JSON parsing:
+
+.. configuration-block::
+
+    .. code-block:: php-symfony
+
+        // src/Service/TombolaService.php
+        namespace App\Service;
+
+        use App\Dto\Cat;
+        use Symfony\Component\DependencyInjection\Attribute\Autowire;
+        use Symfony\Component\JsonStreamer\StreamReaderInterface;
+        use Symfony\Component\TypeInfo\Type;
+
+        class TombolaService
+        {
+            private string $catsJsonFile;
+
+            public function __construct(
+                private StreamReaderInterface $jsonStreamReader,
+                #[Autowire(param: 'kernel.root_dir')]
+                string $rootDir,
+            ) {
+                $this->catsJsonFile = sprintf('%s/var/cats.json', $rootDir);
+            }
+
+            public function pickTheTenthCat(): ?Cat
+            {
+                $jsonResource = fopen($this->catsJsonFile, 'r');
+                $type = Type::iterable(Type::object(Cat::class));
+
+                /** @var iterable<Cat> $cats */
+                $cats = $this->jsonStreamReader->read($jsonResource, $type);
+
+                $i = 0;
+                foreach ($cats as $cat) {
+                    if ($i === 9) {
+                        return $cat;
+                    }
+
+                    ++$i;
+                }
+
+                return null;
+            }
+
+            /**
+             * @return list<string>
+             */
+            public function listEligibleCatNames(): array
+            {
+                $json = file_get_contents($this->catsJsonFile);
+                $type = Type::iterable(Type::object(Cat::class));
+
+                /** @var iterable<Cat> $cats */
+                $cats = $this->jsonStreamReader->read($json, $type);
+
+                return array_map(fn(Cat $cat) => $cat->name, iterator_to_array($cats));
+            }
+        }
+
+    .. code-block:: php-standalone
+
+        // src/Service/TombolaService.php
+        namespace App\Service;
+
+        use App\Dto\Cat;
+        use Symfony\Component\JsonStreamer\JsonStreamReader;
+        use Symfony\Component\JsonStreamer\StreamReaderInterface;
+        use Symfony\Component\TypeInfo\Type;
+
+        class TombolaService
+        {
+            private StreamReaderInterface $jsonStreamReader;
+            private string $catsJsonFile;
+
+            public function __construct(
+                private string $catsJsonFile,
+            ) {
+                $this->jsonStreamReader = JsonStreamReader::create();
+            }
+
+            public function pickTheTenthCat(): ?Cat
+            {
+                $jsonResource = fopen($this->catsJsonFile, 'r');
+                $type = Type::iterable(Type::object(Cat::class));
+
+                /** @var iterable<Cat> $cats */
+                $cats = $this->jsonStreamReader->read($jsonResource, $type);
+
+                $i = 0;
+                foreach ($cats as $cat) {
+                    if ($i === 9) {
+                        return $cat;
+                    }
+
+                    ++$i;
+                }
+
+                return null;
+            }
+
+            /**
+             * @return list<string>
+             */
+            public function listEligibleCatNames(): array
+            {
+                $json = file_get_contents($this->catsJsonFile);
+                $type = Type::iterable(Type::object(Cat::class));
+
+                /** @var iterable<Cat> $cats */
+                $cats = $this->jsonStreamReader->read($json, $type);
+
+                return array_map(fn(Cat $cat) => $cat->name, iterator_to_array($cats));
+            }
+        }
+
+.. tip::
+
+    You can explicitly inject the ``json_streamer.stream_reader`` service by
+    using the ``#[Target('json_streamer.stream_reader')]`` autowire attribute.
+
+The examples above demonstrate two different approaches to decoding JSON data
+using JsonStreamer:
+
+* decoding from a stream (``pickTheTenthCat``)
+* decoding from a string (``listEligibleCatNames``)
+
+Both methods handle the same JSON data but differ in memory usage and performance.
+Use streams if optimizing memory usage is more important. Use strings if
+performance is more important.
+
+Decoding from a Stream
+~~~~~~~~~~~~~~~~~~~~~~
+
+In the ``pickTheTenthCat`` method, the JSON data is read as a stream using
+:phpfunction:`fopen`. This is useful for large files, as the data is processed
+incrementally rather than being fully loaded into memory.
+
+To optimize memory usage, JsonStreamer creates `ghost objects`_ instead of
+fully instantiating them. These lightweight placeholders delay object creation
+until the data is actually needed.
+
+* Advantage: Efficient memory usage, ideal for very large JSON files.
+* Disadvantage: Slightly slower due to lazy loading.
+
+Decoding from a String
+~~~~~~~~~~~~~~~~~~~~~~
+
+In the ``listEligibleCatNames`` method, the entire JSON file is read into a
+string using :phpfunction:`file_get_contents`. The decoder then instantiates
+all the objects immediately.
+
+This approach is faster because all objects are created immediately, but it
+requires more memory.
+
+* Advantage: Faster, ideal for small to medium JSON files.
+* Disadvantage: Higher memory usage, unsuitable for large files.
+
+Enabling PHPDoc Reading
+-----------------------
+
+The JsonStreamer component can read advanced PHPDoc type definitions (e.g.,
+generics) and process complex PHP objects accordingly.
+
+Consider the ``Shelter`` class that defines a generic ``TAnimal`` type, which
+can be a ``Cat`` or a ``Dog``::
+
+    // src/Dto/Shelter.php
+    namespace App\Dto;
+
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+
+    /**
+     * @template TAnimal of Cat|Dog
+     */
+    #[JsonStreamable]
+    class Shelter
+    {
+        /**
+         * @var list<TAnimal>
+         */
+        public array $animals;
+    }
+
+To enable PHPDoc parsing, run:
+
+.. code-block:: terminal
+
+    $ composer require phpstan/phpdoc-parser
+
+Then, when encoding/decoding a ``Shelter`` instance, you can specify the
+concrete type information, and JsonStreamer will correctly interpret the JSON
+structure::
+
+    use App\Dto\Cat;
+    use App\Dto\Shelter;
+    use Symfony\Component\TypeInfo\Type;
+
+    $json = <<<JSON
+    {
+      "animals": [
+        {"name": "Eva", "age": 29},
+        {...}
+      ]
+    }
+    JSON;
+
+    // maps the TAnimal template in Shelter to the Cat concrete type
+    $type = Type::generic(Type::object(Shelter::class), Type::object(Cat::class));
+
+    $catShelter = $jsonStreamReader->read($json, $type); // will be populated with Cat instances
+
+Configuring Encoding/Decoding
+-----------------------------
+
+While it's usually best not to alter the shape or values of objects during
+serialization, sometimes it's necessary.
+
+Configuring the Encoded Name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can configure the JSON key for a property using the
+:class:`Symfony\\Component\\JsonStreamer\\Attribute\\StreamedName` attribute::
+
+    // src/Dto/Duck.php
+    namespace App\Dto;
+
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+    use Symfony\Component\JsonStreamer\Attribute\StreamedName;
+
+    #[JsonStreamable]
+    class Duck
+    {
+        #[StreamedName('@id')]
+        public string $id;
+    }
+
+This maps the ``Duck::$id`` property to the ``@id`` JSON key::
+
+    use App\Dto\Duck;
+    use Symfony\Component\TypeInfo\Type;
+
+    // ...
+
+    $duck = new Duck();
+    $duck->id = '/ducks/daffy';
+
+    echo (string) $jsonStreamWriter->write($duck, Type::object(Duck::class));
+
+    // This will output:
+    // {
+    //   "@id": "/ducks/daffy"
+    // }
+
+Configuring the Encoded Value
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To transform a property's value during encoding, use the
+:class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer`
+attribute. Its ``nativeToStream`` option accepts a callable or a
+:ref:`value transformer service id <json-streamer-transform-with-services>`.
+
+The callable must be a public static method or non-anonymous function with this
+signature::
+
+    $transformer = function (mixed $data, array $options = []): mixed { /* ... */ };
+
+Then specify it in the attribute::
+
+    // src/Dto/Duck.php
+    namespace App\Dto;
+
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+    use Symfony\Component\JsonStreamer\Attribute\ValueTransformer;
+
+    #[JsonStreamable]
+    class Duck
+    {
+        #[ValueTransformer(nativeToStream: 'strtoupper')]
+        public string $name;
+
+        #[ValueTransformer(nativeToStream: [self::class, 'formatHeight'])]
+        public int $height;
+
+        public static function formatHeight(int $value, array $options = []): string
+        {
+            return sprintf('%.2fcm', $value / 100);
+        }
+    }
+
+The following example transforms the ``name`` and ``height`` properties during
+encoding::
+
+    use App\Dto\Duck;
+    use Symfony\Component\TypeInfo\Type;
+
+    // ...
+
+    $duck = new Duck();
+    $duck->name = 'daffy';
+    $duck->height = 5083;
+
+    echo (string) $jsonStreamWriter->write($duck, Type::object(Duck::class));
+
+    // This will output:
+    // {
+    //   "name": "DAFFY",
+    //   "height": "50.83cm"
+    // }
+
+Configuring the Decoded Value
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To transform a property's value during decoding, use the
+:class:`Symfony\\Component\\JsonStreamer\\Attribute\\ValueTransformer`
+attribute. Its ``streamToNative`` option accepts a callable or a
+:ref:`value transformer service id <json-streamer-transform-with-services>`.
+
+The callable must be a public static method or non-anonymous function with this
+signature::
+
+    $valueTransformer = function (mixed $data, array $options = []): mixed { /* ... */ };
+
+Then specify it in the attribute::
+
+    // src/Dto/Duck.php
+    namespace App\Dto;
+
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+    use Symfony\Component\JsonStreamer\Attribute\ValueTransformer;
+
+    #[JsonStreamable]
+    class Duck
+    {
+        #[ValueTransformer(streamToNative: [self::class, 'retrieveFirstName'])]
+        public string $firstName;
+
+        #[ValueTransformer(streamToNative: [self::class, 'retrieveLastName'])]
+        public string $lastName;
+
+        public static function retrieveFirstName(string $normalized, array $options = []): string
+        {
+            return explode(' ', $normalized)[0];
+        }
+
+        public static function retrieveLastName(string $normalized, array $options = []): string
+        {
+            return explode(' ', $normalized)[1];
+        }
+    }
+
+This will extract first and last names from a full name in the input JSON::
+
+    use App\Dto\Duck;
+    use Symfony\Component\TypeInfo\Type;
+
+    // ...
+
+    $duck = $jsonStreamReader->read(
+        '{"name": "Daffy Duck"}',
+        Type::object(Duck::class),
+    );
+
+    // The $duck variable will contain:
+    // object(Duck)#1 (1) {
+    //   ["firstName"] => string(5) "Daffy"
+    //   ["lastName"] => string(4) "Duck"
+    // }
+
+.. _json-streamer-transform-with-services:
+
+Transforming Value Using Services
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When callables are not enough, you can use a service implementing the
+:class:`Symfony\\Component\\JsonStreamer\\ValueTransformer\\ValueTransformerInterface`::
+
+    // src/Transformer/DogUrlTransformer.php
+    namespace App\Transformer;
+
+    use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface;
+    use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+    use Symfony\Component\TypeInfo\Type;
+
+    class DogUrlTransformer implements ValueTransformerInterface
+    {
+        public function __construct(
+            private UrlGeneratorInterface $urlGenerator,
+        ) {
+        }
+
+        public function transform(mixed $value, array $options = []): string
+        {
+            if (!is_int($value)) {
+                throw new \InvalidArgumentException(sprintf('The value must be "int", "%s" given.', get_debug_type($value)));
+            }
+
+            return $this->urlGenerator->generate('show_dog', ['id' => $value]);
+        }
+
+        public static function getStreamValueType(): Type
+        {
+            return Type::string();
+        }
+    }
+
+.. note::
+
+    The ``getStreamValueType()`` method must return the value's type as it will
+    appear in the JSON stream.
+
+To use this transformer in a class, configure the ``#[ValueTransformer]`` attribute::
+
+    // src/Dto/Dog.php
+    namespace App\Dto;
+
+    use App\Transformer\DogUrlTransformer;
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+    use Symfony\Component\JsonStreamer\Attribute\StreamedName;
+    use Symfony\Component\JsonStreamer\Attribute\ValueTransformer;
+
+    #[JsonStreamable]
+    class Dog
+    {
+        #[StreamedName('url')]
+        #[ValueTransformer(nativeToStream: DogUrlTransformer::class)]
+        public int $id;
+    }
+
+.. tip::
+
+    Value transformers are called frequently during encoding and decoding. Keep
+    them lightweight and avoid calls to external APIs or the database.
+
+Configuring Keys and Values Dynamically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+JsonStreamer uses services that implement the
+:class:`Symfony\\Component\\JsonStreamer\\Mapping\\PropertyMetadataLoaderInterface`
+to control the shape and values of objects during encoding/decoding.
+
+These services are highly flexible and can be decorated to support dynamic
+configurations, providing more flexibility than attributes::
+
+    namespace App\Streamer\SensitivePropertyMetadataLoader;
+
+    use App\Dto\SensitiveInterface;
+    use App\Streamer\ValueTransformer\EncryptorValueTransformer;
+    use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
+    use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
+    use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata;
+    use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface;
+    use Symfony\Component\TypeInfo\Type;
+
+    #[AsDecorator('json_streamer.write.property_metadata_loader')]
+    class SensitivePropertyMetadataLoader implements PropertyMetadataLoaderInterface
+    {
+        public function __construct(
+            #[AutowireDecorated]
+            private PropertyMetadataLoaderInterface $decorated,
+        ) {
+        }
+
+        public function load(string $className, array $options = [], array $context = []): array
+        {
+            $propertyMetadataMap = $this->decorated->load($className, $options, $context);
+
+            if (!is_a($className, SensitiveInterface::class, true)) {
+                return $propertyMetadataMap;
+            }
+
+            // you can configure value transformers
+            foreach ($propertyMetadataMap as $jsonKey => $metadata) {
+                if (in_array($metadata->getName(), $className::getPropertiesToEncrypt(), true)) {
+                    $propertyMetadataMap[$jsonKey] = $metadata
+                        ->withType(Type::string())
+                        ->withAdditionalNativeToStreamValueTransformer(EncryptorValueTransformer::class);
+                }
+            }
+
+            // you can remove existing properties
+            foreach ($propertyMetadataMap as $jsonKey => $metadata) {
+                if (in_array($metadata->getName(), $className::getPropertiesToRemove(), true)) {
+                    unset($propertyMetadataMap[$jsonKey]);
+                }
+            }
+
+            // you can rename JSON keys
+            foreach ($propertyMetadataMap as $jsonKey => $metadata) {
+                $propertyMetadataMap[md5($jsonKey)] = $propertyMetadataMap[$jsonKey];
+                unset($propertyMetadataMap[$jsonKey]);
+            }
+
+            // you can add virtual properties
+            $propertyMetadataMap['is_sensitive'] = new PropertyMetadata(
+                name: 'theNameWontBeUsed',
+                type: Type::bool(),
+                nativeToStreamValueTransformers: [fn() => true],
+            );
+
+            return $propertyMetadataMap;
+        }
+    }
+
+Although powerful, this approach introduces complexity. Decorating property
+metadata loaders requires a deep understanding of the internals.
+
+For most use cases, attribute-based configuration is sufficient. Reserve
+dynamic loaders for advanced scenarios.
+
+.. _json-streamer-streamable-attribute:
+
+Marking Objects as Streamable
+-----------------------------
+
+The ``JsonStreamable`` attribute marks a class as streamable. While not strictly
+required, it's highly recommended because it enables cache warm-up to pre-generate
+encoding/decoding files, improving performance.
+
+It includes two optional properties: ``asObject`` and ``asList``, which define
+how the class should be prepared during cache warm-up::
+
+    use Symfony\Component\JsonStreamer\Attribute\JsonStreamable;
+
+    #[JsonStreamable(asObject: true, asList: true)]
+    class StreamableData
+    {
+        // ...
+    }
+
+.. _`DTO classes`: https://en.wikipedia.org/wiki/Data_transfer_object
+.. _ghost objects: https://en.wikipedia.org/wiki/Lazy_loading#Ghost
diff --git a/service_container.rst b/service_container.rst
index f94b15233c3..8b86d06a833 100644
--- a/service_container.rst
+++ b/service_container.rst
@@ -162,10 +162,6 @@ each time you ask for it.
                 # this creates a service per class whose id is the fully-qualified class name
                 App\:
                     resource: '../src/'
-                    exclude:
-                        - '../src/DependencyInjection/'
-                        - '../src/Entity/'
-                        - '../src/Kernel.php'
 
                 # order is important in this file because service definitions
                 # always *replace* previous ones; add your own service configuration below
@@ -187,7 +183,7 @@ each time you ask for it.
 
                     <!-- makes classes in src/ available to be used as services -->
                     <!-- this creates a service per class whose id is the fully-qualified class name -->
-                    <prototype namespace="App\" resource="../src/" exclude="../src/{DependencyInjection,Entity,Kernel.php}"/>
+                    <prototype namespace="App\" resource="../src/"/>
 
                     <!-- order is important in this file because service definitions
                          always *replace* previous ones; add your own service configuration below -->
@@ -212,8 +208,7 @@ each time you ask for it.
 
                 // makes classes in src/ available to be used as services
                 // this creates a service per class whose id is the fully-qualified class name
-                $services->load('App\\', '../src/')
-                    ->exclude('../src/{DependencyInjection,Entity,Kernel.php}');
+                $services->load('App\\', '../src/');
 
                 // order is important in this file because service definitions
                 // always *replace* previous ones; add your own service configuration below
@@ -221,15 +216,57 @@ each time you ask for it.
 
     .. tip::
 
-        The value of the ``resource`` and ``exclude`` options can be any valid
-        `glob pattern`_. The value of the ``exclude`` option can also be an
-        array of glob patterns.
+        The value of the ``resource`` option can be any valid `glob pattern`_.
 
     Thanks to this configuration, you can automatically use any classes from the
     ``src/`` directory as a service, without needing to manually configure
     it. Later, you'll learn how to :ref:`import many services at once
     <service-psr4-loader>` with resource.
 
+    If some files or directories in your project should not become services, you
+    can exclude them using the ``exclude`` option:
+
+    .. configuration-block::
+
+        .. code-block:: yaml
+
+            # config/services.yaml
+            services:
+                # ...
+                App\:
+                    resource: '../src/'
+                    exclude:
+                        - '../src/SomeDirectory/'
+                        - '../src/AnotherDirectory/'
+                        - '../src/SomeFile.php'
+
+        .. code-block:: xml
+
+            <!-- config/services.xml -->
+            <?xml version="1.0" encoding="UTF-8" ?>
+            <container xmlns="http://symfony.com/schema/dic/services"
+                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                xsi:schemaLocation="http://symfony.com/schema/dic/services
+                    https://symfony.com/schema/dic/services/services-1.0.xsd">
+
+                <services>
+                    <prototype namespace="App\" resource="../src/" exclude="../src/{SomeDirectory,AnotherDirectory,Kernel.php}"/>
+                    <!-- ... -->
+                </services>
+            </container>
+
+        .. code-block:: php
+
+            // config/services.php
+            namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+            return function(ContainerConfigurator $container): void {
+                // ...
+
+                $services->load('App\\', '../src/')
+                    ->exclude('../src/{SomeDirectory,AnotherDirectory,Kernel.php}');
+            };
+
     If you'd prefer to manually wire your service, you can
     :ref:`use explicit configuration <services-explicitly-configure-wire-services>`.
 
@@ -260,6 +297,32 @@ as a service in some environments::
         // ...
     }
 
+If you want to exclude a service from being registered in a specific
+environment, you can use the ``#[WhenNot]`` attribute::
+
+    use Symfony\Component\DependencyInjection\Attribute\WhenNot;
+
+    // SomeClass is registered in all environments except "dev"
+
+    #[WhenNot(env: 'dev')]
+    class SomeClass
+    {
+        // ...
+    }
+
+    // you can apply more than one WhenNot attribute to the same class
+
+    #[WhenNot(env: 'dev')]
+    #[WhenNot(env: 'test')]
+    class AnotherClass
+    {
+        // ...
+    }
+
+.. versionadded:: 7.2
+
+    The ``#[WhenNot]`` attribute was introduced in Symfony 7.2.
+
 .. _services-constructor-injection:
 
 Injecting Services/Config into a Service
@@ -935,10 +998,6 @@ Our configuration looks like this:
     Closures can be injected :ref:`by using autowiring <autowiring_closures>`
     and its dedicated attributes.
 
-.. versionadded:: 6.1
-
-    The ``closure`` argument type was introduced in Symfony 6.1.
-
 .. _services-binding:
 
 Binding Arguments by Name or Type
@@ -1159,20 +1218,32 @@ to them.
 Linting Service Definitions
 ---------------------------
 
-The ``lint:container`` command checks that the arguments injected into services
-match their type declarations. It's useful to run it before deploying your
+The ``lint:container`` command performs additional checks to ensure the container
+is properly configured. It is useful to run this command before deploying your
 application to production (e.g. in your continuous integration server):
 
 .. code-block:: terminal
 
     $ php bin/console lint:container
 
-Checking the types of all service arguments whenever the container is compiled
-can hurt performance. That's why this type checking is implemented in a
-:doc:`compiler pass </service_container/compiler_passes>` called
-``CheckTypeDeclarationsPass`` which is disabled by default and enabled only when
-executing the ``lint:container`` command. If you don't mind the performance
-loss, enable the compiler pass in your application.
+    # optionally, you can force the resolution of environment variables;
+    # the command will fail if any of those environment variables are missing
+    $ php bin/console lint:container --resolve-env-vars
+
+.. versionadded:: 7.2
+
+    The ``--resolve-env-vars`` option was introduced in Symfony 7.2.
+
+Performing those checks whenever the container is compiled can hurt performance.
+That's why they are implemented in :doc:`compiler passes </service_container/compiler_passes>`
+called ``CheckTypeDeclarationsPass`` and ``CheckAliasValidityPass``, which are
+disabled by default and enabled only when executing the ``lint:container`` command.
+If you don't mind the performance loss, you can enable these compiler passes in
+your application.
+
+.. versionadded:: 7.1
+
+    The ``CheckAliasValidityPass`` compiler pass was introduced in Symfony 7.1.
 
 .. _container-public:
 
@@ -1309,11 +1380,6 @@ key. For example, the default Symfony configuration contains this:
     may use the :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Exclude`
     attribute directly on your class to exclude it.
 
-    .. versionadded:: 6.3
-
-        The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Exclude`
-        attribute was introduced in Symfony 6.3.
-
 This can be used to quickly make many classes available as services and apply some
 default configuration. The ``id`` of each service is its fully-qualified class name.
 You can override any service that's imported by using its id (class name) below
@@ -1592,11 +1658,6 @@ Thanks to the ``#[AutowireCallable]`` attribute, you can now inject this
         }
     }
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable`
-    attribute was introduced in Symfony 6.3.
-
 Instead of using the ``#[AutowireCallable]`` attribute, you can also generate
 an adapter for a functional interface through configuration:
 
diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst
index a3663c2195d..22bf649d861 100644
--- a/service_container/alias_private.rst
+++ b/service_container/alias_private.rst
@@ -165,10 +165,6 @@ services.
             $services->alias('app.mailer', PhpMailer::class);
         };
 
-.. versionadded:: 6.3
-
-    The ``#[AsAlias]`` attribute was introduced in Symfony 6.3.
-
 This means that when using the container directly, you can access the
 ``PhpMailer`` service by asking for the ``app.mailer`` service like this::
 
@@ -185,6 +181,32 @@ This means that when using the container directly, you can access the
             # ...
             app.mailer: '@App\Mail\PhpMailer'
 
+The ``#[AsAlias]`` attribute can also be limited to one or more specific
+:ref:`config environments <configuration-environments>` using the ``when`` argument::
+
+    // src/Mail/PhpMailer.php
+    namespace App\Mail;
+
+    // ...
+    use Symfony\Component\DependencyInjection\Attribute\AsAlias;
+
+    #[AsAlias(id: 'app.mailer', when: 'dev')]
+    class PhpMailer
+    {
+        // ...
+    }
+
+    // pass an array to apply it in multiple config environments
+    #[AsAlias(id: 'app.mailer', when: ['dev', 'test'])]
+    class PhpMailer
+    {
+        // ...
+    }
+
+.. versionadded:: 7.3
+
+    The ``when`` argument of the ``#[AsAlias]`` attribute was introduced in Symfony 7.3.
+
 .. tip::
 
     When using ``#[AsAlias]`` attribute, you may omit passing ``id`` argument
diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst
index ec25f2d7dae..ea1bf1b12ff 100644
--- a/service_container/autowiring.rst
+++ b/service_container/autowiring.rst
@@ -640,10 +640,6 @@ logic about those arguments::
         }
     }
 
-.. versionadded:: 6.1
-
-    The ``#[Autowire]`` attribute was introduced in Symfony 6.1.
-
 The ``#[Autowire]`` attribute can also be used for :ref:`parameters <service-parameters>`,
 :doc:`complex expressions </service_container/expression_language>` and even
 :ref:`environment variables <config-env-vars>` ,
@@ -682,10 +678,6 @@ The ``#[Autowire]`` attribute can also be used for :ref:`parameters <service-par
         // ...
     }
 
-.. versionadded:: 6.3
-
-    The ``param`` and ``env`` arguments were introduced in Symfony 6.3.
-
 .. _autowiring_closures:
 
 Generate Closures With Autowiring
@@ -741,11 +733,6 @@ attribute::
         }
     }
 
-.. versionadded:: 6.3
-
-    The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireServiceClosure`
-    attribute was introduced in Symfony 6.3.
-
 It is common that a service accepts a closure with a specific signature.
 In this case, you can use the
 :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable` attribute
@@ -782,10 +769,35 @@ attribute. By doing so, the callable will automatically be lazy, which means
 that the encapsulated service will be instantiated **only** at the
 closure's first call.
 
-.. versionadded:: 6.3
+The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireMethodOf`
+attribute provides a simpler way of specifying the name of the service method
+by using the property name as method name::
+
+    // src/Service/MessageGenerator.php
+    namespace App\Service;
+
+    use Symfony\Component\DependencyInjection\Attribute\AutowireMethodOf;
+
+    class MessageGenerator
+    {
+        public function __construct(
+            #[AutowireMethodOf('third_party.remote_message_formatter')]
+            private \Closure $format,
+        ) {
+        }
+
+        public function generate(string $message): void
+        {
+            $formattedMessage = ($this->format)($message);
+
+            // ...
+        }
+    }
 
-    The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireCallable`
-    attribute was introduced in Symfony 6.3.
+.. versionadded:: 7.1
+
+    The :class:`Symfony\Component\DependencyInjection\Attribute\\AutowireMethodOf`
+    attribute was introduced in Symfony 7.1.
 
 .. _autowiring-calls:
 
@@ -850,6 +862,40 @@ typed properties:
             }
         }
 
+Autowiring Anonymous Services Inline
+------------------------------------
+
+.. versionadded:: 7.1
+
+   The ``#[AutowireInline]`` attribute was added in Symfony 7.1.
+
+Similar to how anonymous services can be defined inline in configuration files,
+the :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireInline`
+attribute allows you to declare anonymous services inline, directly next to their
+corresponding arguments::
+
+    public function __construct(
+        #[AutowireInline(
+            factory: [ScopingHttpClient::class, 'forBaseUri'],
+            arguments: [
+                '$baseUri' => 'https://api.example.com',
+                '$defaultOptions' => [
+                    'auth_bearer' => '%env(EXAMPLE_TOKEN)%',
+                ],
+            ]
+        )]
+        private HttpClientInterface $client,
+    ) {
+    }
+
+This example tells Symfony to inject an object created by calling the
+``ScopingHttpClient::forBaseUri()`` factory with the specified base URI and
+default options. This is just one example: you can use the ``#[AutowireInline]``
+attribute to define any kind of anonymous service.
+
+While this approach is convenient for simple service definitions, consider moving
+complex or heavily configured services to a configuration file to ease maintenance.
+
 Autowiring Controller Action Methods
 ------------------------------------
 
diff --git a/service_container/debug.rst b/service_container/debug.rst
index e8f0022f1a2..9e3e28a5343 100644
--- a/service_container/debug.rst
+++ b/service_container/debug.rst
@@ -32,7 +32,7 @@ Partial search is also available:
 .. code-block:: terminal
 
     $ php bin/console debug:container --tag=kernel
-    
+
     Select one of the following tags to display its information:
      [0] kernel.event_listener
      [1] kernel.event_subscriber
@@ -42,10 +42,6 @@ Partial search is also available:
      [5] kernel.fragment_renderer
      [6] kernel.cache_clearer
 
-.. versionadded:: 6.2
-
-    The partial search was introduced in Symfony 6.2.
-
 Detailed Info about a Single Service
 ------------------------------------
 
@@ -56,5 +52,8 @@ its id:
 
     $ php bin/console debug:container App\Service\Mailer
 
-    # to show the service arguments:
-    $ php bin/console debug:container App\Service\Mailer --show-arguments
+.. deprecated:: 7.3
+
+    Starting in Symfony 7.3, this command displays the service arguments by default.
+    In earlier Symfony versions, you needed to use the ``--show-arguments`` option,
+    which is now deprecated.
diff --git a/service_container/expression_language.rst b/service_container/expression_language.rst
index 7847a87b3b8..41c538db468 100644
--- a/service_container/expression_language.rst
+++ b/service_container/expression_language.rst
@@ -76,10 +76,6 @@ In this context, you have access to 3 functions:
 ``env``
     Returns the value of an env variable.
 
-.. versionadded:: 6.1
-
-    The ``env()`` function was introduced in Symfony 6.1.
-
 You also have access to the :class:`Symfony\\Component\\DependencyInjection\\Container`
 via a ``container`` variable. Here's another example:
 
@@ -126,7 +122,3 @@ via a ``container`` variable. Here's another example:
 Expressions can be used in ``arguments``, ``properties``, as arguments with
 ``configurator``, as arguments to ``calls`` (method calls) and in
 ``factories`` (:doc:`service factories </service_container/factories>`).
-
-.. versionadded:: 6.1
-
-    Using expressions in ``factories`` was introduced in Symfony 6.1.
diff --git a/service_container/factories.rst b/service_container/factories.rst
index a2643eb6440..9864287d57a 100644
--- a/service_container/factories.rst
+++ b/service_container/factories.rst
@@ -230,10 +230,6 @@ as the factory class:
                 ->constructor('create');
         };
 
-.. versionadded:: 6.3
-
-    The ``constructor`` option was introduced in Symfony 6.3.
-
 Non-Static Factories
 --------------------
 
@@ -376,10 +372,6 @@ method name:
 Using Expressions in Service Factories
 --------------------------------------
 
-.. versionadded:: 6.1
-
-    Using expressions as factories was introduced in Symfony 6.1.
-
 Instead of using PHP classes as a factory, you can also use
 :doc:`expressions </service_container/expression_language>`. This allows you to
 e.g. change the service based on a parameter:
diff --git a/service_container/import.rst b/service_container/import.rst
index 91021762eae..47af34d3a34 100644
--- a/service_container/import.rst
+++ b/service_container/import.rst
@@ -82,7 +82,6 @@ a relative or absolute path to the imported file:
 
             App\:
                 resource: '../src/*'
-                exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
 
             # ...
 
@@ -104,8 +103,7 @@ a relative or absolute path to the imported file:
             <services>
                 <defaults autowire="true" autoconfigure="true"/>
 
-                <prototype namespace="App\" resource="../src/*"
-                    exclude="../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}"/>
+                <prototype namespace="App\" resource="../src/*"/>
 
                 <!-- ... -->
             </services>
@@ -127,8 +125,7 @@ a relative or absolute path to the imported file:
                     ->autoconfigure()
             ;
 
-            $services->load('App\\', '../src/*')
-                ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}');
+            $services->load('App\\', '../src/*');
         };
 
 When loading a configuration file, Symfony first processes all imported files in
diff --git a/service_container/lazy_services.rst b/service_container/lazy_services.rst
index 9af730867de..abb3c2cca7f 100644
--- a/service_container/lazy_services.rst
+++ b/service_container/lazy_services.rst
@@ -26,14 +26,6 @@ until you interact with the proxy in some way.
     Lazy services do not support `final`_ or ``readonly`` classes, but you can use
     `Interface Proxifying`_ to work around this limitation.
 
-    In PHP versions prior to 8.0 lazy services do not support parameters with
-    default values for built-in PHP classes (e.g. ``PDO``).
-
-.. versionadded:: 6.2
-
-    Starting from Symfony 6.2, service laziness is supported out of the box
-    without having to install any additional package.
-
 .. _lazy-services_configuration:
 
 Configuration
@@ -83,11 +75,6 @@ same signature of the class representing the service should be injected. A lazy
 itself when being accessed for the first time). The same happens when calling
 ``Container::get()`` directly.
 
-To check if your lazy service works you can check the interface of the received object::
-
-    dump(class_implements($service));
-    // the output should include "Symfony\Component\VarExporter\LazyObjectInterface"
-
 You can also configure your service's laziness thanks to the
 :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Autoconfigure` attribute.
 For example, to define your service as lazy use the following::
@@ -129,10 +116,31 @@ laziness, and supports lazy-autowiring of union types::
     ) {
     }
 
-.. versionadded:: 6.3
+Another possibility is to use the :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Lazy` attribute::
+
+    namespace App\Twig;
+
+    use Symfony\Component\DependencyInjection\Attribute\Lazy;
+    use Twig\Extension\ExtensionInterface;
+
+    #[Lazy]
+    class AppExtension implements ExtensionInterface
+    {
+        // ...
+    }
+
+This attribute can be applied to both class and parameters that should be lazy-loaded.
+It defines an optional parameter used to define interfaces for proxy and intersection types::
+
+    public function __construct(
+        #[Lazy(FooInterface::class)]
+        FooInterface|BarInterface $foo,
+    ) {
+    }
+
+.. versionadded:: 7.1
 
-    The ``lazy`` argument of the ``#[Autowire]`` attribute was introduced in
-    Symfony 6.3.
+    The ``#[Lazy]`` attribute was introduced in Symfony 7.1.
 
 Interface Proxifying
 --------------------
diff --git a/service_container/service_closures.rst b/service_container/service_closures.rst
index cedbaaa2bf9..88b0ab64002 100644
--- a/service_container/service_closures.rst
+++ b/service_container/service_closures.rst
@@ -52,6 +52,13 @@ argument of type ``service_closure``:
                 # In case the dependency is optional
                 # arguments: [!service_closure '@?mailer']
 
+            # you can also use the special '@>' syntax as a shortcut of '!service_closure'
+            App\Service\AnotherService:
+                arguments: ['@>mailer']
+
+                # the shortcut also works for optional dependencies
+                # arguments: ['@>?mailer']
+
     .. code-block:: xml
 
         <!-- config/services.xml -->
@@ -90,6 +97,10 @@ argument of type ``service_closure``:
             //     ->args([service_closure('mailer')->ignoreOnInvalid()]);
         };
 
+.. versionadded:: 7.3
+
+    The ``@>`` shortcut syntax for YAML was introduced in Symfony 7.3.
+
 .. seealso::
 
     Service closures can be injected :ref:`by using autowiring <autowiring_closures>`
diff --git a/service_container/service_decoration.rst b/service_container/service_decoration.rst
index 7bf1fb9165d..e2cadbb0a4b 100644
--- a/service_container/service_decoration.rst
+++ b/service_container/service_decoration.rst
@@ -123,10 +123,6 @@ but keeps a reference of the old one as ``.inner``:
                 ->decorate(Mailer::class);
         };
 
-.. versionadded:: 6.1
-
-    The ``#[AsDecorator]`` attribute was introduced in Symfony 6.1.
-
 The ``decorates`` option tells the container that the ``App\DecoratingMailer``
 service replaces the ``App\Mailer`` service. If you're using the
 :ref:`default services.yaml configuration <service-container-services-load-example>`,
@@ -211,12 +207,6 @@ automatically changed to ``'.inner'``):
                 ->args([service('.inner')]);
         };
 
-.. deprecated:: 6.3
-
-    The ``#[MapDecorated]`` attribute is deprecated since Symfony 6.3.
-    Instead, use the
-    :class:`#[AutowireDecorated] <Symfony\\Component\\DependencyInjection\\Attribute\\AutowireDecorated>` attribute.
-
 .. note::
 
     The visibility of the decorated ``App\Mailer`` service (which is an alias
diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst
index d67384d50dd..9026478cf33 100644
--- a/service_container/service_subscribers_locators.rst
+++ b/service_container/service_subscribers_locators.rst
@@ -110,17 +110,35 @@ in the service subscriber::
     that you have :ref:`autoconfigure <services-autoconfigure>` enabled. You
     can also manually add the ``container.service_subscriber`` tag.
 
-The injected service is an instance of :class:`Symfony\\Component\\DependencyInjection\\ServiceLocator`
-which implements both the PSR-11 ``ContainerInterface`` and :class:`Symfony\\Contracts\\Service\\ServiceProviderInterface`.
-It is also a callable and a countable::
+A service locator is a `PSR-11 container`_ that contains a set of services,
+but only instantiates them when they are actually used. Consider the following code::
+
+    // ...
+    $handler = $this->locator->get($commandClass);
+
+    return $handler->handle($command);
+
+In this example, the ``$handler`` service is only instantiated when the
+``$this->locator->get($commandClass)`` method is called.
+
+You can also type-hint the service locator argument with
+:class:`Symfony\\Contracts\\Service\\ServiceCollectionInterface` instead of
+``Psr\Container\ContainerInterface``. By doing so, you'll be able to
+count and iterate over the services of the locator::
 
     // ...
     $numberOfHandlers = count($this->locator);
     $nameOfHandlers = array_keys($this->locator->getProvidedServices());
-    // ...
-    $handler = ($this->locator)($commandClass);
 
-    return $handler->handle($command);
+    // you can iterate through all services of the locator
+    foreach ($this->locator as $serviceId => $service) {
+        // do something with the service, the service id or both
+    }
+
+.. versionadded:: 7.1
+
+    The :class:`Symfony\\Contracts\\Service\\ServiceCollectionInterface` was
+    introduced in Symfony 7.1.
 
 Including Services
 ------------------
@@ -247,17 +265,13 @@ service type to a service.
 Add Dependency Injection Attributes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.2
-
-    The ability to add attributes was introduced in Symfony 6.2.
-
 As an alternate to aliasing services in your configuration, you can also configure
 the following dependency injection attributes in the ``getSubscribedServices()``
 method directly:
 
 * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Autowire`
-* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator`
-* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator`
+* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator`
+* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator`
 * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Target`
 * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireDecorated`
 
@@ -268,8 +282,8 @@ This is done by having ``getSubscribedServices()`` return an array of
     use Psr\Container\ContainerInterface;
     use Psr\Log\LoggerInterface;
     use Symfony\Component\DependencyInjection\Attribute\Autowire;
-    use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
-    use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
+    use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
+    use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
     use Symfony\Component\DependencyInjection\Attribute\Target;
     use Symfony\Contracts\Service\Attribute\SubscribedService;
 
@@ -285,14 +299,22 @@ This is done by having ``getSubscribedServices()`` return an array of
             // Target
             new SubscribedService('event.logger', LoggerInterface::class, attributes: new Target('eventLogger')),
 
-            // TaggedIterator
-            new SubscribedService('loggers', 'iterable', attributes: new TaggedIterator('logger.tag')),
+            // AutowireIterator
+            new SubscribedService('loggers', 'iterable', attributes: new AutowireIterator('logger.tag')),
 
-            // TaggedLocator
-            new SubscribedService('handlers', ContainerInterface::class, attributes: new TaggedLocator('handler.tag')),
+            // AutowireLocator
+            new SubscribedService('handlers', ContainerInterface::class, attributes: new AutowireLocator('handler.tag')),
         ];
     }
 
+.. deprecated:: 7.1
+
+    The :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator`
+    and :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator`
+    attributes were deprecated in Symfony 7.1 in favor of
+    :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator`
+    and :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator`.
+
 .. note::
 
     The above example requires using ``3.2`` version or newer of ``symfony/service-contracts``.
@@ -375,12 +397,6 @@ attribute::
         }
     }
 
-.. versionadded:: 6.4
-
-    The
-    :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator`
-    attribute was introduced in Symfony 6.4.
-
 .. _service-locator_autowire-iterator:
 
 The AutowireIterator Attribute
@@ -419,12 +435,6 @@ For example, to collect all handlers for different command types, use the
         }
     }
 
-.. versionadded:: 6.4
-
-    The
-    :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator`
-    attribute was introduced in Symfony 6.4.
-
 .. _service-subscribers-locators_defining-service-locator:
 
 Defining a Service Locator
@@ -460,13 +470,13 @@ or directly via PHP attributes:
         namespace App;
 
         use Psr\Container\ContainerInterface;
-        use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
 
         class CommandBus
         {
             public function __construct(
                 // creates a service locator with all the services tagged with 'app.handler'
-                #[TaggedLocator('app.handler')]
+                #[AutowireLocator('app.handler')]
                 private ContainerInterface $locator,
             ) {
             }
@@ -702,12 +712,12 @@ to index the services:
         namespace App;
 
         use Psr\Container\ContainerInterface;
-        use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
 
         class CommandBus
         {
             public function __construct(
-                #[TaggedLocator('app.handler', indexAttribute: 'key')]
+                #[AutowireLocator('app.handler', indexAttribute: 'key')]
                 private ContainerInterface $locator,
             ) {
             }
@@ -817,12 +827,12 @@ get the value used to index the services:
         namespace App;
 
         use Psr\Container\ContainerInterface;
-        use Symfony\Component\DependencyInjection\Attribute\TaggedLocator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
 
         class CommandBus
         {
             public function __construct(
-                #[TaggedLocator('app.handler', defaultIndexMethod: 'getLocatorKey')]
+                #[AutowireLocator('app.handler', defaultIndexMethod: 'getLocatorKey')]
                 private ContainerInterface $locator,
             ) {
             }
@@ -887,7 +897,7 @@ the following order:
 Service Subscriber Trait
 ------------------------
 
-The :class:`Symfony\\Contracts\\Service\\ServiceSubscriberTrait` provides an
+The :class:`Symfony\\Contracts\\Service\\ServiceMethodsSubscriberTrait` provides an
 implementation for :class:`Symfony\\Contracts\\Service\\ServiceSubscriberInterface`
 that looks through all methods in your class that are marked with the
 :class:`Symfony\\Contracts\\Service\\Attribute\\SubscribedService` attribute. It
@@ -901,12 +911,12 @@ services based on type-hinted helper methods::
     use Psr\Log\LoggerInterface;
     use Symfony\Component\Routing\RouterInterface;
     use Symfony\Contracts\Service\Attribute\SubscribedService;
+    use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
     use Symfony\Contracts\Service\ServiceSubscriberInterface;
-    use Symfony\Contracts\Service\ServiceSubscriberTrait;
 
     class MyService implements ServiceSubscriberInterface
     {
-        use ServiceSubscriberTrait;
+        use ServiceMethodsSubscriberTrait;
 
         public function doSomething(): void
         {
@@ -927,6 +937,11 @@ services based on type-hinted helper methods::
         }
     }
 
+.. versionadded:: 7.1
+
+    The ``ServiceMethodsSubscriberTrait`` was introduced in Symfony 7.1.
+    In previous Symfony versions it was called ``ServiceSubscriberTrait``.
+
 This  allows you to create helper traits like RouterAware, LoggerAware, etc...
 and compose your services with them::
 
@@ -963,12 +978,12 @@ and compose your services with them::
     // src/Service/MyService.php
     namespace App\Service;
 
+    use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
     use Symfony\Contracts\Service\ServiceSubscriberInterface;
-    use Symfony\Contracts\Service\ServiceSubscriberTrait;
 
     class MyService implements ServiceSubscriberInterface
     {
-        use ServiceSubscriberTrait, LoggerAware, RouterAware;
+        use ServiceMethodsSubscriberTrait, LoggerAware, RouterAware;
 
         public function doSomething(): void
         {
@@ -986,16 +1001,12 @@ and compose your services with them::
 ``SubscribedService`` Attributes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-.. versionadded:: 6.2
-
-    The ability to add attributes was introduced in Symfony 6.2.
-
 You can use the ``attributes`` argument of ``SubscribedService`` to add any
 of the following dependency injection attributes:
 
 * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Autowire`
-* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedIterator`
-* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\TaggedLocator`
+* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireIterator`
+* :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireLocator`
 * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Target`
 * :class:`Symfony\\Component\\DependencyInjection\\Attribute\\AutowireDecorated`
 
@@ -1009,12 +1020,12 @@ Here's an example::
     use Symfony\Component\DependencyInjection\Attribute\Target;
     use Symfony\Component\Routing\RouterInterface;
     use Symfony\Contracts\Service\Attribute\SubscribedService;
+    use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait;
     use Symfony\Contracts\Service\ServiceSubscriberInterface;
-    use Symfony\Contracts\Service\ServiceSubscriberTrait;
 
     class MyService implements ServiceSubscriberInterface
     {
-        use ServiceSubscriberTrait;
+        use ServiceMethodsSubscriberTrait;
 
         public function doSomething(): void
         {
@@ -1097,3 +1108,4 @@ Another alternative is to mock it using ``PHPUnit``::
     // ...
 
 .. _`Command pattern`: https://en.wikipedia.org/wiki/Command_pattern
+.. _`PSR-11 container`: https://www.php-fig.org/psr/psr-11/
diff --git a/service_container/tags.rst b/service_container/tags.rst
index f905ed1895e..3a547042de7 100644
--- a/service_container/tags.rst
+++ b/service_container/tags.rst
@@ -155,22 +155,30 @@ In a Symfony application, call this method in your kernel class::
         }
     }
 
-In a Symfony bundle, call this method in the ``load()`` method of the
-:doc:`bundle extension class </bundles/extension>`::
+In bundles extending the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
+class, call this method in the ``loadExtension()`` method of the main bundle class::
 
-    // src/DependencyInjection/MyBundleExtension.php
-    class MyBundleExtension extends Extension
-    {
-        // ...
+    // ...
+    use Symfony\Component\DependencyInjection\ContainerBuilder;
+    use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+    use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
 
-        public function load(array $configs, ContainerBuilder $container): void
+    class MyBundle extends AbstractBundle
+    {
+        public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
         {
-            $container->registerForAutoconfiguration(CustomInterface::class)
+            $builder
+                ->registerForAutoconfiguration(CustomInterface::class)
                 ->addTag('app.custom_tag')
             ;
         }
     }
 
+.. note::
+
+    For bundles not extending the ``AbstractBundle`` class, call this method in
+    the ``load()`` method of the :doc:`bundle extension class </bundles/extension>`.
+
 Autoconfiguration registering is not limited to interfaces. It is possible
 to use PHP attributes to autoconfigure services by using the
 :method:`Symfony\\Component\\DependencyInjection\\ContainerBuilder::registerAttributeForAutoconfiguration`
@@ -458,6 +466,8 @@ or from your kernel::
     :ref:`components documentation <components-di-compiler-pass>` for more
     information.
 
+.. _tags_additional-attributes:
+
 Adding Additional Attributes on Tags
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -548,10 +558,6 @@ To answer this, change the service declaration:
             ;
         };
 
-.. versionadded:: 6.2
-
-    Support for attributes as array was introduced in Symfony 6.2.
-
 .. tip::
 
     The ``name`` attribute is used by default to define the name of the tag.
@@ -676,13 +682,13 @@ directly via PHP attributes:
         // src/HandlerCollection.php
         namespace App;
 
-        use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
         class HandlerCollection
         {
             public function __construct(
                 // the attribute must be applied directly to the argument to autowire
-                #[TaggedIterator('app.handler')]
+                #[AutowireIterator('app.handler')]
                 iterable $handlers
             ) {
             }
@@ -752,7 +758,7 @@ directly via PHP attributes:
 
 .. note::
 
-    Some IDEs will show an error when using ``#[TaggedIterator]`` together
+    Some IDEs will show an error when using ``#[AutowireIterator]`` together
     with the `PHP constructor promotion`_:
     *"Attribute cannot be applied to a property because it does not contain the 'Attribute::TARGET_PROPERTY' flag"*.
     The reason is that those constructor arguments are both parameters and class
@@ -768,12 +774,12 @@ iterator, add the ``exclude`` option:
         // src/HandlerCollection.php
         namespace App;
 
-        use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
         class HandlerCollection
         {
             public function __construct(
-                #[TaggedIterator('app.handler', exclude: ['App\Handler\Three'])]
+                #[AutowireIterator('app.handler', exclude: ['App\Handler\Three'])]
                 iterable $handlers
             ) {
             }
@@ -851,12 +857,12 @@ disabled by setting the ``exclude_self`` option to ``false``:
         // src/HandlerCollection.php
         namespace App;
 
-        use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
         class HandlerCollection
         {
             public function __construct(
-                #[TaggedIterator('app.handler', exclude: ['App\Handler\Three'], excludeSelf: false)]
+                #[AutowireIterator('app.handler', exclude: ['App\Handler\Three'], excludeSelf: false)]
                 iterable $handlers
             ) {
             }
@@ -923,15 +929,6 @@ disabled by setting the ``exclude_self`` option to ``false``:
             ;
         };
 
-.. versionadded:: 6.1
-
-    The ``exclude`` option was introduced in Symfony 6.1.
-
-.. versionadded:: 6.3
-
-    The ``exclude_self`` option and the automatic exclusion of the referencing
-    service in the injected iterable were introduced in Symfony 6.3.
-
 .. seealso::
 
     See also :doc:`tagged locator services </service_container/service_subscribers_locators>`
@@ -1010,12 +1007,12 @@ you can define it in the configuration of the collecting service:
         // src/HandlerCollection.php
         namespace App;
 
-        use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
         class HandlerCollection
         {
             public function __construct(
-                #[TaggedIterator('app.handler', defaultPriorityMethod: 'getPriority')]
+                #[AutowireIterator('app.handler', defaultPriorityMethod: 'getPriority')]
                 iterable $handlers
             ) {
             }
@@ -1084,12 +1081,12 @@ to index the services:
         // src/HandlerCollection.php
         namespace App;
 
-        use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
         class HandlerCollection
         {
             public function __construct(
-                #[TaggedIterator('app.handler', indexAttribute: 'key')]
+                #[AutowireIterator('app.handler', indexAttribute: 'key')]
                 iterable $handlers
             ) {
             }
@@ -1198,12 +1195,12 @@ get the value used to index the services:
         // src/HandlerCollection.php
         namespace App;
 
-        use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
+        use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
 
         class HandlerCollection
         {
             public function __construct(
-                #[TaggedIterator('app.handler', defaultIndexMethod: 'getIndex')]
+                #[AutowireIterator('app.handler', defaultIndexMethod: 'getIndex')]
                 iterable $handlers
             ) {
             }
@@ -1292,4 +1289,19 @@ be used directly on the class of the service you want to configure::
         // ...
     }
 
+You can apply the ``#[AsTaggedItem]`` attribute multiple times to register the
+same service under different indexes::
+
+    #[AsTaggedItem(index: 'handler_one', priority: 5)]
+    #[AsTaggedItem(index: 'handler_two', priority: 20)]
+    class SomeService
+    {
+        // ...
+    }
+
+.. versionadded:: 7.3
+
+    The feature to apply the ``#[AsTaggedItem]`` attribute multiple times was
+    introduced in Symfony 7.3.
+
 .. _`PHP constructor promotion`: https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion
diff --git a/session.rst b/session.rst
index 1426614e3af..1594cc7eebe 100644
--- a/session.rst
+++ b/session.rst
@@ -115,7 +115,7 @@ sessions for anonymous users, you must *completely* avoid accessing the session.
 .. note::
 
     Sessions will also be started when using features that rely on them internally,
-    such as the :ref:`CSRF protection in forms <csrf-protection-forms>`.
+    such as the :ref:`stateful CSRF protection in forms <csrf-protection-forms>`.
 
 .. _flash-messages:
 
@@ -425,6 +425,11 @@ Check out the Symfony config reference to learn more about the other available
     ``session.auto_start = 1`` This directive should be turned off in
     ``php.ini``, in the web server directives or in ``.htaccess``.
 
+.. deprecated:: 7.2
+
+    The ``sid_length`` and ``sid_bits_per_character`` options were deprecated
+    in Symfony 7.2 and will be ignored in Symfony 8.0.
+
 The session cookie is also available in :ref:`the Response object <component-http-foundation-response>`.
 This is useful to get that cookie in the CLI context or when using PHP runners
 like Roadrunner or Swoole.
@@ -487,12 +492,11 @@ the ``php.ini`` directive ``session.gc_maxlifetime``. The meaning in this contex
 that any stored session that was saved more than ``gc_maxlifetime`` ago should be
 deleted. This allows one to expire records based on idle time.
 
-However, some operating systems (e.g. Debian) do their own session handling and set
-the ``session.gc_probability`` variable to ``0`` to stop PHP doing garbage
-collection. That's why Symfony now overwrites this value to ``1``.
-
-If you wish to use the original value set in your ``php.ini``, add the following
-configuration:
+However, some operating systems (e.g. Debian) manage session handling differently
+and set the ``session.gc_probability`` variable to ``0`` to prevent PHP from performing
+garbage collection. By default, Symfony uses the value of the ``gc_probability``
+directive set in the ``php.ini`` file. If you can't modify this PHP setting, you
+can configure it directly in Symfony:
 
 .. code-block:: yaml
 
@@ -500,14 +504,19 @@ configuration:
     framework:
         session:
             # ...
-            gc_probability: null
+            gc_probability: 1
 
-You can configure these settings by passing ``gc_probability``, ``gc_divisor``
-and ``gc_maxlifetime`` in an array to the constructor of
+Alternatively, you can configure these settings by passing ``gc_probability``,
+``gc_divisor`` and ``gc_maxlifetime`` in an array to the constructor of
 :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage`
 or to the :method:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage::setOptions`
 method.
 
+.. versionadded:: 7.2
+
+    Using the ``php.ini`` directive as the default value for ``gc_probability``
+    was introduced in Symfony 7.2.
+
 .. _session-database:
 
 Store Sessions in a Database
diff --git a/setup.rst b/setup.rst
index 2b1c3b86f85..a7fa8c66826 100644
--- a/setup.rst
+++ b/setup.rst
@@ -4,7 +4,7 @@ Installing & Setting up the Symfony Framework
 .. admonition:: Screencast
     :class: screencast
 
-    Do you prefer video tutorials? Check out the `Harmonious Development with Symfony`_
+    Do you prefer video tutorials? Check out the `Cosmic Coding with Symfony`_
     screencast series.
 
 .. _symfony-tech-requirements:
@@ -14,7 +14,7 @@ Technical Requirements
 
 Before creating your first Symfony application you must:
 
-* Install PHP 8.1 or higher and these PHP extensions (which are installed and
+* Install PHP 8.2 or higher and these PHP extensions (which are installed and
   enabled by default in most PHP 8 installations): `Ctype`_, `iconv`_,
   `PCRE`_, `Session`_, `SimpleXML`_, and `Tokenizer`_;
 * `Install Composer`_, which is used to install PHP packages.
@@ -48,10 +48,10 @@ application:
 .. code-block:: terminal
 
     # run this if you are building a traditional web application
-    $ symfony new my_project_directory --version="6.4.*" --webapp
+    $ symfony new my_project_directory --version="7.3.x" --webapp
 
     # run this if you are building a microservice, console application or API
-    $ symfony new my_project_directory --version="6.4.*"
+    $ symfony new my_project_directory --version="7.3.x"
 
 The only difference between these two commands is the number of packages
 installed by default. The ``--webapp`` option installs extra packages to give
@@ -63,12 +63,12 @@ Symfony application using Composer:
 .. code-block:: terminal
 
     # run this if you are building a traditional web application
-    $ composer create-project symfony/skeleton:"6.4.*" my_project_directory
+    $ composer create-project symfony/skeleton:"7.3.x" my_project_directory
     $ cd my_project_directory
     $ composer require webapp
 
     # run this if you are building a microservice, console application or API
-    $ composer create-project symfony/skeleton:"6.4.*" my_project_directory
+    $ composer create-project symfony/skeleton:"7.3.x" my_project_directory
 
 No matter which command you run to create the Symfony application. All of them
 will create a new ``my_project_directory/`` directory, download some dependencies
@@ -311,7 +311,7 @@ Learn More
     setup/web_server_configuration
     setup/*
 
-.. _`Harmonious Development with Symfony`: https://symfonycasts.com/screencast/symfony
+.. _`Cosmic Coding with Symfony`: https://symfonycasts.com/screencast/symfony
 .. _`Install Composer`: https://getcomposer.org/download/
 .. _`install the Symfony CLI`: https://symfony.com/download
 .. _`symfony-cli/symfony-cli GitHub repository`: https://github.com/symfony-cli/symfony-cli
diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst
index ab05f2b202b..9c4db187d51 100644
--- a/setup/upgrade_major.rst
+++ b/setup/upgrade_major.rst
@@ -1,4 +1,4 @@
-Upgrading a Major Version (e.g. 5.4.0 to 6.0.0)
+Upgrading a Major Version (e.g. 6.4.0 to 7.0.0)
 ===============================================
 
 Every two years, Symfony releases a new major version release (the first number
@@ -27,10 +27,10 @@ backwards incompatible changes. To accomplish this, the "old" (e.g. functions,
 classes, etc) code still works, but is marked as *deprecated*, indicating that
 it will be removed/changed in the future and that you should stop using it.
 
-When the major version is released (e.g. 6.0.0), all deprecated features and
+When the major version is released (e.g. 7.0.0), all deprecated features and
 functionality are removed. So, as long as you've updated your code to stop
 using these deprecated features in the last version before the major (e.g.
-``5.4.*``), you should be able to upgrade without a problem. That means that
+``6.4.*``), you should be able to upgrade without a problem. That means that
 you should first :doc:`upgrade to the last minor version </setup/upgrade_minor>`
 (e.g. 5.4) so that you can see *all* the deprecations.
 
@@ -107,7 +107,7 @@ done!
 .. sidebar:: Using the Weak Deprecations Mode
 
     Sometimes, you can't fix all deprecations (e.g. something was deprecated
-    in 5.4 and you still need to support 5.3). In these cases, you can still
+    in 6.4 and you still need to support 6.3). In these cases, you can still
     use the bridge to fix as many deprecations as possible and then allow
     more of them to make your tests pass again. You can do this by using the
     ``SYMFONY_DEPRECATIONS_HELPER`` env variable:
@@ -144,12 +144,10 @@ starting with ``symfony/`` to the new major version:
           "...": "...",
 
           "require": {
-    -         "symfony/cache": "5.4.*",
-    +         "symfony/cache": "6.0.*",
-    -         "symfony/config": "5.4.*",
-    +         "symfony/config": "6.0.*",
-    -         "symfony/console": "5.4.*",
-    +         "symfony/console": "6.0.*",
+    -         "symfony/config": "6.4.*",
+    +         "symfony/config": "7.0.*",
+    -         "symfony/console": "6.4.*",
+    +         "symfony/console": "7.0.*",
               "...": "...",
 
               "...": "A few libraries starting with symfony/ follow their own
@@ -157,7 +155,7 @@ starting with ``symfony/`` to the new major version:
                       symfony/ux-[...], symfony/[...]-bundle).
                       You do not need to update these versions: you can
                       upgrade them independently whenever you want",
-              "symfony/monolog-bundle": "^3.5",
+              "symfony/monolog-bundle": "^3.10",
           },
           "...": "...",
       }
@@ -174,11 +172,11 @@ dependency management and Composer update performance:
           "...": "...",
 
           "require": {
-    -         "symfony/cache": "6.0.*",
+    -         "symfony/cache": "7.0.*",
     +         "symfony/cache": "*",
-    -         "symfony/config": "6.0.*",
+    -         "symfony/config": "7.0.*",
     +         "symfony/config": "*",
-    -         "symfony/console": "6.0.*",
+    -         "symfony/console": "7.0.*",
     +         "symfony/console": "*",
               "...": "...",
           },
@@ -186,7 +184,7 @@ dependency management and Composer update performance:
 
     +     "extra": {
     +         "symfony": {
-    +             "require": "6.0.*"
+    +             "require": "7.0.*"
     +         }
     +     }
       }
@@ -241,13 +239,13 @@ included in the Symfony repository for any BC break that you need to be aware of
 Upgrading to Symfony 6: Add Native Return Types
 -----------------------------------------------
 
-Symfony 6 will come with native PHP return types to (almost all) methods.
+Symfony 6 and Symfony 7 added native PHP return types to (almost all) methods.
 
 In PHP, if the parent has a return type declaration, any class implementing
 or overriding the method must have the return type as well. However, you
 can add a return type before the parent adds one. This means that it is
 important to add the native PHP return types to your classes before
-upgrading to Symfony 6.0. Otherwise, you will get incompatible declaration
+upgrading to Symfony 6.0 or 7.0. Otherwise, you will get incompatible declaration
 errors.
 
 When debug mode is enabled (typically in the dev and test environment),
diff --git a/setup/upgrade_minor.rst b/setup/upgrade_minor.rst
index 9e8c6943d1f..ec00e142b82 100644
--- a/setup/upgrade_minor.rst
+++ b/setup/upgrade_minor.rst
@@ -1,4 +1,4 @@
-Upgrading a Minor Version (e.g. 5.0.0 to 5.1.0)
+Upgrading a Minor Version (e.g. 6.3.0 to 6.4.0)
 ===============================================
 
 If you're upgrading a minor version (where the middle number changes), then
@@ -21,7 +21,7 @@ There are two steps to upgrading a minor version:
 The ``composer.json`` file is configured to allow Symfony packages to be
 upgraded to patch versions. But to upgrade to a new minor version, you will
 probably need to update the version constraint next to each library starting
-``symfony/``. Suppose you are upgrading from Symfony 5.3 to 5.4:
+``symfony/``. Suppose you are upgrading from Symfony 6.3 to 6.4:
 
 .. code-block:: diff
 
@@ -29,19 +29,17 @@ probably need to update the version constraint next to each library starting
           "...": "...",
 
           "require": {
-    -         "symfony/cache": "5.3.*",
-    +         "symfony/cache": "5.4.*",
-    -         "symfony/config": "5.3.*",
-    +         "symfony/config": "5.4.*",
-    -         "symfony/console": "5.3.*",
-    +         "symfony/console": "5.4.*",
+    -         "symfony/config": "6.3.*",
+    +         "symfony/config": "6.4.*",
+    -         "symfony/console": "6.3.*",
+    +         "symfony/console": "6.4.*",
               "...": "...",
 
               "...": "A few libraries starting with
                       symfony/ follow their own versioning scheme. You
                       do not need to update these versions: you can
                       upgrade them independently whenever you want",
-              "symfony/monolog-bundle": "^3.5",
+              "symfony/monolog-bundle": "^3.10",
           },
           "...": "...",
       }
@@ -54,8 +52,8 @@ Your ``composer.json`` file should also have an ``extra`` block that you will
       "extra": {
           "symfony": {
               "...": "...",
-    -         "require": "5.3.*"
-    +         "require": "5.4.*"
+    -         "require": "6.3.*"
+    +         "require": "6.4.*"
           }
       }
 
@@ -79,7 +77,7 @@ to your code to get everything working. Additionally, some features you're
 using might still work, but might now be deprecated. While that's fine,
 if you know about these deprecations, you can start to fix them over time.
 
-Every version of Symfony comes with an UPGRADE file (e.g. `UPGRADE-5.4.md`_)
+Every version of Symfony comes with an UPGRADE file (e.g. `UPGRADE-6.4.md`_)
 included in the Symfony directory that describes these changes. If you follow
 the instructions in the document and update your code accordingly, it should be
 safe to update in the future.
@@ -97,5 +95,5 @@ These documents can also be found in the `Symfony Repository`_.
 .. include:: /setup/_update_recipes.rst.inc
 
 .. _`Symfony Repository`: https://github.com/symfony/symfony
-.. _`UPGRADE-5.4.md`: https://github.com/symfony/symfony/blob/5.4/UPGRADE-5.4.md
+.. _`UPGRADE-6.4.md`: https://github.com/symfony/symfony/blob/6.4/UPGRADE-6.4.md
 .. _`Rector`: https://github.com/rectorphp/rector
diff --git a/components/string.rst b/string.rst
similarity index 87%
rename from components/string.rst
rename to string.rst
index 0cf0583da6c..e51e7d1b502 100644
--- a/components/string.rst
+++ b/string.rst
@@ -1,11 +1,11 @@
-The String Component
-====================
+Creating and Manipulating Strings
+=================================
 
-    The String component provides a single object-oriented API to work with
-    three "unit systems" of strings: bytes, code points and grapheme clusters.
+Symfony provides an object-oriented API to work with Unicode strings (as bytes,
+code points and grapheme clusters). This API is available via the String component,
+which you must first install in your application:
 
-Installation
-------------
+.. _installation:
 
 .. code-block:: terminal
 
@@ -203,7 +203,10 @@ Methods to Change Case
 ::
 
     // changes all graphemes/code points to lower case
-    u('FOO Bar')->lower();  // 'foo bar'
+    u('FOO Bar Brİan')->lower();  // 'foo bar bri̇an'
+    // changes all graphemes/code points to lower case according to locale-specific case mappings
+    u('FOO Bar Brİan')->localeLower('en');  // 'foo bar bri̇an'
+    u('FOO Bar Brİan')->localeLower('lt');  // 'foo bar bri̇̇an'
 
     // when dealing with different languages, uppercase/lowercase is not enough
     // there are three cases (lower, upper, title), some characters have no case,
@@ -213,18 +216,41 @@ Methods to Change Case
     u('Die O\'Brian Straße')->folded(); // "die o'brian strasse"
 
     // changes all graphemes/code points to upper case
-    u('foo BAR')->upper(); // 'FOO BAR'
+    u('foo BAR bάz')->upper(); // 'FOO BAR BΆZ'
+    // changes all graphemes/code points to upper case according to locale-specific case mappings
+    u('foo BAR bάz')->localeUpper('en'); // 'FOO BAR BΆZ'
+    u('foo BAR bάz')->localeUpper('el'); // 'FOO BAR BAZ'
 
     // changes all graphemes/code points to "title case"
-    u('foo bar')->title();     // 'Foo bar'
-    u('foo bar')->title(allWords: true); // 'Foo Bar'
+    u('foo ijssel')->title();               // 'Foo ijssel'
+    u('foo ijssel')->title(allWords: true); // 'Foo Ijssel'
+    // changes all graphemes/code points to "title case" according to locale-specific case mappings
+    u('foo ijssel')->localeTitle('en'); // 'Foo ijssel'
+    u('foo ijssel')->localeTitle('nl'); // 'Foo IJssel'
 
     // changes all graphemes/code points to camelCase
     u('Foo: Bar-baz.')->camel(); // 'fooBarBaz'
     // changes all graphemes/code points to snake_case
     u('Foo: Bar-baz.')->snake(); // 'foo_bar_baz'
-    // other cases can be achieved by chaining methods. E.g. PascalCase:
-    u('Foo: Bar-baz.')->camel()->title(); // 'FooBarBaz'
+    // changes all graphemes/code points to kebab-case
+    u('Foo: Bar-baz.')->kebab(); // 'foo-bar-baz'
+    // changes all graphemes/code points to PascalCase
+    u('Foo: Bar-baz.')->pascal(); // 'FooBarBaz'
+    // other cases can be achieved by chaining methods, e.g. :
+    u('Foo: Bar-baz.')->camel()->upper(); // 'FOOBARBAZ'
+
+.. versionadded:: 7.1
+
+    The ``localeLower()``, ``localeUpper()`` and ``localeTitle()`` methods were
+    introduced in Symfony 7.1.
+
+.. versionadded:: 7.2
+
+    The ``kebab()`` method was introduced in Symfony 7.2.
+
+.. versionadded:: 7.3
+
+    The ``pascal()`` method was introduced in Symfony 7.3.
 
 The methods of all string classes are case-sensitive by default. You can perform
 case-insensitive operations with the ``ignoreCase()`` method::
@@ -381,10 +407,19 @@ Methods to Join, Split, Truncate and Reverse
     u('Lorem Ipsum')->truncate(80);            // 'Lorem Ipsum'
     // the second argument is the character(s) added when a string is cut
     // (the total length includes the length of this character(s))
-    u('Lorem Ipsum')->truncate(8, '…');             // 'Lorem I…'
-    // if the third argument is false, the last word before the cut is kept
-    // even if that generates a string longer than the desired length
-    u('Lorem Ipsum')->truncate(8, '…', cut: false); // 'Lorem Ipsum'
+    // (note that '…' is a single character that includes three dots; it's not '...')
+    u('Lorem Ipsum')->truncate(8, '…');        // 'Lorem I…'
+    // the third optional argument defines how to cut words when the length is exceeded
+    // the default value is TruncateMode::Char which cuts the string at the exact given length
+    u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::Char);       // 'Lorem ip'
+    // returns up to the last complete word that fits in the given length without surpassing it
+    u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::WordBefore); // 'Lorem'
+    // returns up to the last complete word that fits in the given length, surpassing it if needed
+    u('Lorem ipsum dolor sit amet')->truncate(8, cut: TruncateMode::WordAfter);   // 'Lorem ipsum'
+
+.. versionadded:: 7.2
+
+    The ``TruncateMode`` parameter for truncate function was introduced in Symfony 7.2.
 
 ::
 
@@ -493,6 +528,13 @@ requested during the program execution. You can also create lazy strings from a
     // hash computation only if it's needed
     $lazyHash = LazyString::fromStringable(new Hash());
 
+Working with Emojis
+-------------------
+
+These contents have been moved to the :doc:`Emoji component docs </emoji>`.
+
+.. _string-slugger:
+
 Slugger
 -------
 
@@ -565,11 +607,8 @@ the injected slugger is the same as the request locale::
 Slug Emojis
 ~~~~~~~~~~~
 
-.. versionadded:: 6.2
-
-    The Emoji transliteration feature was introduced in Symfony 6.2.
-
-You can transform any emojis into their textual representation::
+You can also combine the :ref:`emoji transliterator <emoji-transliteration>`
+with the slugger to transform any emojis into their textual representation::
 
     use Symfony\Component\String\Slugger\AsciiSlugger;
 
@@ -583,7 +622,7 @@ You can transform any emojis into their textual representation::
     // $slug = 'un-chat-qui-sourit-chat-noir-et-un-tete-de-lion-vont-au-parc-national';
 
 If you want to use a specific locale for the emoji, or to use the short codes
-from GitHub or Slack, use the first argument of ``withEmoji()`` method::
+from GitHub, Gitlab or Slack, use the first argument of ``withEmoji()`` method::
 
     use Symfony\Component\String\Slugger\AsciiSlugger;
 
@@ -593,20 +632,6 @@ from GitHub or Slack, use the first argument of ``withEmoji()`` method::
     $slug = $slugger->slug('a 😺, 🐈‍⬛, and a 🦁');
     // $slug = 'a-smiley-cat-black-cat-and-a-lion';
 
-If you want to strip emojis from slugs, use the special ``strip`` locale::
-
-    use Symfony\Component\String\Slugger\AsciiSlugger;
-
-    $slugger = new AsciiSlugger();
-    $slugger = $slugger->withEmoji('strip');
-
-    $slug = $slugger->slug('a 😺, 🐈‍⬛, and a 🦁');
-    // $slug = 'a-and-a';
-
-.. versionadded:: 6.3
-
-    The option to strip emojis from slugs was introduced in Symfony 6.3.
-
 .. _string-inflector:
 
 Inflector
@@ -641,11 +666,28 @@ class to convert English words from/to singular/plural with confidence::
 The value returned by both methods is always an array because sometimes it's not
 possible to determine a unique singular/plural form for the given word.
 
+Symfony also provides inflectors for other languages::
+
+    use Symfony\Component\String\Inflector\FrenchInflector;
+
+    $inflector = new FrenchInflector();
+    $result = $inflector->singularize('souris'); // ['souris']
+    $result = $inflector->pluralize('hôpital');  // ['hôpitaux']
+
+    use Symfony\Component\String\Inflector\SpanishInflector;
+
+    $inflector = new SpanishInflector();
+    $result = $inflector->singularize('aviones'); // ['avión']
+    $result = $inflector->pluralize('miércoles'); // ['miércoles']
+
+.. versionadded:: 7.2
+
+    The ``SpanishInflector`` class was introduced in Symfony 7.2.
+
 .. note::
 
-    Symfony also provides a :class:`Symfony\\Component\\String\\Inflector\\FrenchInflector`
-    and an :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface` if
-    you need to implement your own inflector.
+    Symfony provides an :class:`Symfony\\Component\\String\\Inflector\\InflectorInterface`
+    in case you need to implement your own inflector.
 
 .. _`ASCII`: https://en.wikipedia.org/wiki/ASCII
 .. _`Unicode`: https://en.wikipedia.org/wiki/Unicode
diff --git a/templates.rst b/templates.rst
index 6678f653790..fc353384202 100644
--- a/templates.rst
+++ b/templates.rst
@@ -393,19 +393,6 @@ gives you access to these variables:
 ``app.enabled_locales``
     The locales enabled in the application.
 
-.. versionadded:: 6.2
-
-    The ``app.current_route`` and ``app.current_route_parameters`` variables
-    were introduced in Symfony 6.2.
-
-.. versionadded:: 6.3
-
-    The ``app.locale`` variable was introduced in Symfony 6.3.
-
-.. versionadded:: 6.4
-
-    The ``app.enabled_locales`` variable was introduced in Symfony 6.4.
-
 In addition to the global ``app`` variable injected by Symfony, you can also
 inject variables automatically to all Twig templates as explained in the next
 section.
@@ -614,10 +601,6 @@ to define the template to render::
         }
     }
 
-.. versionadded:: 6.2
-
-    The ``#[Template]`` attribute was introduced in Symfony 6.2.
-
 The :ref:`base AbstractController <the-base-controller-classes-services>` also provides the
 :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::renderBlock`
 and :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::renderBlockView`
@@ -657,12 +640,30 @@ This might come handy when dealing with blocks in
 :ref:`templates inheritance <template_inheritance-layouts>` or when using
 `Turbo Streams`_.
 
-.. versionadded:: 6.4
+Similarly, you can use the ``#[Template]`` attribute on the controller to specify
+a block to render::
+
+    // src/Controller/ProductController.php
+    namespace App\Controller;
+
+    use Symfony\Bridge\Twig\Attribute\Template;
+    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+    use Symfony\Component\HttpFoundation\Response;
+
+    class ProductController extends AbstractController
+    {
+        #[Template('product.html.twig', block: 'price_block')]
+        public function price(): array
+        {
+            return [
+                // ...
+            ];
+        }
+    }
+
+.. versionadded:: 7.2
 
-    The
-    :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::renderBlock` and
-    :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController::renderBlockView`
-    methods were introduced in Symfony 6.4.
+    The ``#[Template]`` attribute's ``block`` argument was introduced in Symfony 7.2.
 
 Rendering a Template in Services
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -737,6 +738,11 @@ provided by Symfony:
                     site_name: 'ACME'
                     theme: 'dark'
 
+                # optionally you can define HTTP headers to add to the response
+                headers:
+                    Content-Type: 'text/html'
+                    foo: 'bar'
+
     .. code-block:: xml
 
         <!-- config/routes.xml -->
@@ -766,6 +772,11 @@ provided by Symfony:
                     <default key="site_name">ACME</default>
                     <default key="theme">dark</default>
                 </default>
+
+                <!-- optionally you can define HTTP headers to add to the response -->
+                <default key="headers">
+                    <default key="Content-Type">text/html</default>
+                </default>
             </route>
         </routes>
 
@@ -796,11 +807,20 @@ provided by Symfony:
                     'context' => [
                         'site_name' => 'ACME',
                         'theme' => 'dark',
+                        ],
+
+                    // optionally you can define HTTP headers to add to the response
+                    'headers' => [
+                        'Content-Type' => 'text/html',
                     ]
                 ])
             ;
         };
 
+.. versionadded:: 7.2
+
+    The ``headers`` option was introduced in Symfony 7.2.
+
 Checking if a Template Exists
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -848,9 +868,20 @@ errors. It's useful to run it before deploying your application to production
     $ php bin/console lint:twig templates/article/recent_list.html.twig
 
     # you can also show the deprecated features used in your templates
-    # (only the first deprecation is shown, so run multiple times to catch all)
     $ php bin/console lint:twig --show-deprecations templates/email/
 
+    # you can also excludes directories
+    $ php bin/console lint:twig templates/ --excludes=data_collector --excludes=dev_tool
+
+.. versionadded:: 7.1
+
+    The option to exclude directories was introduced in Symfony 7.1.
+
+.. versionadded:: 7.3
+
+    Before Symfony 7.3, the ``--show-deprecations`` option only displayed the
+    first deprecation found, so you had to run the command repeatedly.
+
 When running the linter inside `GitHub Actions`_, the output is automatically
 adapted to the format required by GitHub, but you can force that format too:
 
@@ -916,10 +947,6 @@ depending on your needs:
         </a>
     {% endfor %}
 
-.. versionadded:: 6.3
-
-    The option to use named arguments in ``dump()`` was introduced in Symfony 6.3.
-
 To avoid leaking sensitive information, the ``dump()`` function/tag is only
 available in the ``dev`` and ``test`` :ref:`configuration environments <configuration-environments>`.
 If you try to use it in the ``prod`` environment, you will see a PHP error.
@@ -1524,23 +1551,20 @@ as currency:
     {# pass in the 3 optional arguments #}
     {{ product.price|price(2, ',', '.') }}
 
-Create a class that extends ``AbstractExtension`` and fill in the logic::
+.. _templates-twig-filter-attribute:
+
+Create a regular PHP class with a method that contains the filter logic. Then,
+add the ``#[AsTwigFilter]`` attribute to define the name and options of
+the Twig filter::
 
     // src/Twig/AppExtension.php
     namespace App\Twig;
 
-    use Twig\Extension\AbstractExtension;
-    use Twig\TwigFilter;
+    use Twig\Attribute\AsTwigFilter;
 
-    class AppExtension extends AbstractExtension
+    class AppExtension
     {
-        public function getFilters(): array
-        {
-            return [
-                new TwigFilter('price', [$this, 'formatPrice']),
-            ];
-        }
-
+        #[AsTwigFilter('price')]
         public function formatPrice(float $number, int $decimals = 0, string $decPoint = '.', string $thousandsSep = ','): string
         {
             $price = number_format($number, $decimals, $decPoint, $thousandsSep);
@@ -1550,24 +1574,19 @@ Create a class that extends ``AbstractExtension`` and fill in the logic::
         }
     }
 
-If you want to create a function instead of a filter, define the
-``getFunctions()`` method::
+.. _templates-twig-function-attribute:
+
+If you want to create a function instead of a filter, use the
+``#[AsTwigFunction]`` attribute::
 
     // src/Twig/AppExtension.php
     namespace App\Twig;
 
-    use Twig\Extension\AbstractExtension;
-    use Twig\TwigFunction;
+    use Twig\Attribute\AsTwigFunction;
 
-    class AppExtension extends AbstractExtension
+    class AppExtension
     {
-        public function getFunctions(): array
-        {
-            return [
-                new TwigFunction('area', [$this, 'calculateArea']),
-            ];
-        }
-
+        #[AsTwigFunction('area')]
         public function calculateArea(int $width, int $length): int
         {
             return $width * $length;
@@ -1579,6 +1598,18 @@ If you want to create a function instead of a filter, define the
     Along with custom filters and functions, you can also register
     `global variables`_.
 
+.. versionadded:: 7.3
+
+    Support for the ``#[AsTwigFilter]``, ``#[AsTwigFunction]`` and ``#[AsTwigTest]``
+    attributes was introduced in Symfony 7.3. Previously, you had to extend the
+    ``AbstractExtension`` class, and override the ``getFilters()`` and ``getFunctions()``
+    methods.
+
+If you're using the :ref:`default services.yaml configuration <service-container-services-load-example>`,
+the :ref:`service autoconfiguration <services-autoconfigure>` feature will enable
+this class as a Twig extension. Otherwise, you need to define a service manually
+and :doc:`tag it </service_container/tags>` with the ``twig.attribute_extension`` tag.
+
 Register an Extension as a Service
 ..................................
 
@@ -1602,10 +1633,11 @@ this command to confirm that your new filter was successfully registered:
 Creating Lazy-Loaded Twig Extensions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Including the code of the custom filters/functions in the Twig extension class
-is the simplest way to create extensions. However, Twig must initialize all
-extensions before rendering any template, even if the template doesn't use an
-extension.
+When :ref:`using attributes to extend Twig <templates-twig-filter-attribute>`,
+the **Twig extensions are already lazy-loaded** and you don't have to do anything
+else. However, if your Twig extensions follow the **legacy approach** of extending
+the ``AbstractExtension`` class, Twig initializes all the extensions before
+rendering any template, even if they are not used.
 
 If extensions don't define dependencies (i.e. if you don't inject services in
 them) performance is not affected. However, if extensions define lots of complex
diff --git a/testing.rst b/testing.rst
index 042f381caa6..2174e7cf874 100644
--- a/testing.rst
+++ b/testing.rst
@@ -323,11 +323,6 @@ concrete one::
 No further configuration is required, as the test service container is a special one
 that allows you to interact with private services and aliases.
 
-.. versionadded:: 6.3
-
-    The possibility to set a private service with the test service container
-    without declaring a public alias for it was introduced in Symfony 6.3.
-
 .. _testing-databases:
 
 Configuring a Database for Tests
@@ -722,6 +717,29 @@ stores in the session of the test client. If you need to define custom
 attributes in this token, you can use the ``tokenAttributes`` argument of the
 :method:`Symfony\\Bundle\\FrameworkBundle\\KernelBrowser::loginUser` method.
 
+You can also use an :ref:`in-memory user <security-memory-user-provider>` in your tests
+by instantiating :class:`Symfony\\Component\\Security\\Core\\User\\InMemoryUser` directly::
+
+    // tests/Controller/ProfileControllerTest.php
+    use Symfony\Component\Security\Core\User\InMemoryUser;
+
+    $client = static::createClient();
+    $testUser = new InMemoryUser('admin', 'password', ['ROLE_ADMIN']);
+    $client->loginUser($testUser);
+
+Before doing this, you must define the in-memory user in your test environment
+configuration to ensure it exists and can be authenticated::
+
+.. code-block:: yaml
+
+    # config/packages/security.yaml
+    when@test:
+        security:
+            users_in_memory:
+                memory:
+                    users:
+                        admin: { password: password, roles: ROLE_ADMIN }
+
 To set a specific firewall (``main`` is set by default)::
 
     $client->loginUser($testUser, 'my_firewall');
@@ -731,12 +749,6 @@ To set a specific firewall (``main`` is set by default)::
     By design, the ``loginUser()`` method doesn't work when using stateless firewalls.
     Instead, add the appropriate token/header in each ``request()`` call.
 
-.. versionadded:: 6.4
-
-    The ``tokenAttributes`` argument of the
-    :method:`Symfony\\Bundle\\FrameworkBundle\\KernelBrowser::loginUser` method
-    was introduced in Symfony 6.4.
-
 Making AJAX Requests
 ....................
 
@@ -979,11 +991,11 @@ However, Symfony provides useful shortcut methods for the most common cases:
 Response Assertions
 ...................
 
-``assertResponseIsSuccessful(string $message = '')``
+``assertResponseIsSuccessful(string $message = '', bool $verbose = true)``
     Asserts that the response was successful (HTTP status is 2xx).
-``assertResponseStatusCodeSame(int $expectedCode, string $message = '')``
+``assertResponseStatusCodeSame(int $expectedCode, string $message = '', bool $verbose = true)``
     Asserts a specific HTTP status code.
-``assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '')``
+``assertResponseRedirects(?string $expectedLocation = null, ?int $expectedCode = null, string $message = '', bool $verbose = true)``
     Asserts the response is a redirect response (optionally, you can check
     the target location and status code). The excepted location can be either
     an absolute or a relative path.
@@ -1001,13 +1013,12 @@ Response Assertions
     Asserts the response format returned by the
     :method:`Symfony\\Component\\HttpFoundation\\Response::getFormat` method
     is the same as the expected value.
-``assertResponseIsUnprocessable(string $message = '')``
+``assertResponseIsUnprocessable(string $message = '', bool $verbose = true)``
     Asserts the response is unprocessable (HTTP status is 422)
 
-.. versionadded:: 6.4
+.. versionadded:: 7.1
 
-    The support for relative path in ``assertResponseRedirects()`` was introduced
-    in Symfony 6.4.
+    The ``$verbose`` parameters were introduced in Symfony 7.1.
 
 Request Assertions
 ..................
@@ -1070,15 +1081,6 @@ Crawler Assertions
     Asserts that value of the field of the first form matching the given
     selector does (not) equal the expected value.
 
-.. versionadded:: 6.3
-
-    The ``assertSelectorCount()`` method was introduced in Symfony 6.3.
-
-.. versionadded:: 6.4
-
-    The ``assertAnySelectorTextContains()``, ``assertAnySelectorTextNotContains()``
-    and ``assertAnySelectorTextSame()`` were introduced in Symfony 6.4.
-
 .. _mailer-assertions:
 
 Mailer Assertions
@@ -1116,18 +1118,13 @@ Mailer Assertions
     Asserts that the subject of the given email does (not) contain the
     expected subject.
 
-.. versionadded:: 6.4
-
-    The ``assertEmailSubjectContains()`` and ``assertEmailSubjectNotContains()``
-    assertions were introduced in Symfony 6.4.
-
 Notifier Assertions
 ...................
 
-``assertNotificationCount(int $count, string $transportName = null, string $message = '')``
+``assertNotificationCount(int $count, ?string $transportName = null, string $message = '')``
     Asserts that the given number of notifications has been created
     (in total or for the given transport).
-``assertQueuedNotificationCount(int $count, string $transportName = null, string $message = '')``
+``assertQueuedNotificationCount(int $count, ?string $transportName = null, string $message = '')``
     Asserts that the given number of notifications are queued
     (in total or for the given transport).
 ``assertNotificationIsQueued(MessageEvent $event, string $message = '')``
@@ -1147,10 +1144,6 @@ Notifier Assertions
     Asserts that the name of the transport for the given notification
     is not the same as the given text.
 
-.. versionadded:: 6.2
-
-    The Notifier assertions were introduced in Symfony 6.2.
-
 HttpClient Assertions
 .....................
 
@@ -1159,7 +1152,7 @@ HttpClient Assertions
     For all the following assertions, ``$client->enableProfiler()`` must be
     called before the code that will trigger HTTP request(s).
 
-``assertHttpClientRequest(string $expectedUrl, string $expectedMethod = 'GET', string|array $expectedBody = null, array $expectedHeaders = [], string $httpClientId = 'http_client')``
+``assertHttpClientRequest(string $expectedUrl, string $expectedMethod = 'GET', string|array|null $expectedBody = null, array $expectedHeaders = [], string $httpClientId = 'http_client')``
     Asserts that the given URL has been called using, if specified,
     the given method body and headers. By default it will check on the HttpClient,
     but you can also pass a specific HttpClient ID.
@@ -1174,10 +1167,6 @@ HttpClient Assertions
     By default it will check on the HttpClient, but you can also pass a specific
     HttpClient ID.
 
-.. versionadded:: 6.4
-
-    The HttpClient assertions were introduced in Symfony 6.4.
-
 End to End Tests (E2E)
 ~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/testing/http_authentication.rst b/testing/http_authentication.rst
deleted file mode 100644
index 8262bf3769d..00000000000
--- a/testing/http_authentication.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-How to Simulate HTTP Authentication in a Functional Test
-========================================================
-
-.. warning::
-
-    Starting from Symfony 5.1, a ``loginUser()`` method was introduced to
-    ease testing secured applications. See :ref:`testing_logging_in_users`
-    for more information about this.
-
-    If you are still using an older version of Symfony, view
-    `previous versions of this article`_ for information on how to simulate
-    HTTP authentication.
-
-.. _previous versions of this article: https://symfony.com/doc/5.0/testing/http_authentication.html
diff --git a/translation.rst b/translation.rst
index 2f0206563ee..ed656c62848 100644
--- a/translation.rst
+++ b/translation.rst
@@ -416,6 +416,84 @@ You can also specify the message domain and pass some additional variables:
     major difference: automatic output escaping is **not** applied to translations
     using a tag.
 
+Global Translation Parameters
+-----------------------------
+
+.. versionadded:: 7.3
+
+    The global translation parameters feature was introduced in Symfony 7.3.
+
+If the content of a translation parameter is repeated across multiple
+translation messages (e.g. a company name, or a version number), you can define
+it as a global translation parameter. This helps you avoid repeating the same
+values manually in each message.
+
+You can configure these global parameters in the ``translations.globals`` option
+of your main configuration file using either ``%...%`` or ``{...}`` syntax:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/translator.yaml
+        translator:
+            # ...
+            globals:
+                # when using the '%' wrapping characters, you must escape them
+                '%%app_name%%': 'My application'
+                '{app_version}': '1.2.3'
+                '{url}': { message: 'url', parameters: { scheme: 'https://' }, domain: 'global' }
+
+    .. code-block:: xml
+
+           <!-- config/packages/translation.xml -->
+           <?xml version="1.0" encoding="UTF-8" ?>
+           <container xmlns="http://symfony.com/schema/dic/services"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xmlns:framework="http://symfony.com/schema/dic/symfony"
+               xsi:schemaLocation="http://symfony.com/schema/dic/services
+                   https://symfony.com/schema/dic/services/services-1.0.xsd
+                   http://symfony.com/schema/dic/symfony
+                   https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
+
+               <framework:config>
+                   <framework:translator>
+                       <!-- ... -->
+                        <!-- when using the '%' wrapping characters, you must escape them -->
+                       <framework:global name="%%app_name%%">My application</framework:global>
+                       <framework:global name="{app_version}" value="1.2.3"/>
+                       <framework:global name="{url}" message="url" domain="global">
+                            <framework:parameter name="scheme">https://</framework:parameter>
+                        </framework:global>
+                   </framework:translator>
+               </framework:config>
+           </container>
+
+    .. code-block:: php
+
+        // config/packages/translator.php
+        use Symfony\Config\TwigConfig;
+
+        return static function (TwigConfig $translator): void {
+            // ...
+            // when using the '%' wrapping characters, you must escape them
+            $translator->globals('%%app_name%%')->value('My application');
+            $translator->globals('{app_version}')->value('1.2.3');
+            $translator->globals('{url}')->value(['message' => 'url', 'parameters' => ['scheme' => 'https://']]);
+        };
+
+Once defined, you can use these parameters in translation messages anywhere in
+your application:
+
+.. code-block:: twig
+
+    {{ 'Application version: {app_version}'|trans }}
+    {# output: "Application version: 1.2.3" #}
+
+    {# parameters passed to the message override global parameters #}
+    {{ 'Package version: {app_version}'|trans({'{app_version}': '2.3.4'}) }}
+    # Displays "Package version: 2.3.4"
+
 Forcing the Translator Locale
 -----------------------------
 
@@ -457,11 +535,6 @@ The ``translation:extract`` command looks for missing translations in:
 * Any PHP file/class stored in the ``src/`` directory that uses
   :ref:`Constraints Attributes <validation-constraints>`  with ``*message`` named argument(s).
 
-.. versionadded:: 6.2
-
-    The support of PHP files/classes that use constraint attributes was
-    introduced in Symfony 6.2.
-
 .. tip::
 
     Install the ``nikic/php-parser`` package in your project to improve the
@@ -472,10 +545,6 @@ The ``translation:extract`` command looks for missing translations in:
 
         $ composer require nikic/php-parser
 
-    .. versionadded:: 6.2
-
-        The AST parser support was introduced in Symfony 6.2.
-
 By default, when the ``translation:extract`` command creates new entries in the
 translation file, it uses the same content as both the source and the pending
 translation. The only difference is that the pending translation is prefixed by
@@ -485,6 +554,20 @@ translation. The only difference is that the pending translation is prefixed by
 
     $ php bin/console translation:extract --force --prefix="NEW_" fr
 
+Alternatively, you can use the ``--no-fill`` option to leave the pending translation
+completely empty when creating new entries in the translation catalog. This is
+particularly useful when using external translation tools, as it makes it easier
+to spot untranslated strings:
+
+.. code-block:: terminal
+
+    # when using the --no-fill option, the --prefix option is ignored
+    $ php bin/console translation:extract --force --no-fill fr
+
+.. versionadded:: 7.2
+
+    The ``--no-fill`` option was introduced in Symfony 7.2.
+
 .. _translation-resource-locations:
 
 Translation Resource/File Names and Locations
@@ -530,10 +613,6 @@ provides many loaders which are selected based on the following file extensions:
 * ``.po``: `Portable object format`_;
 * ``.qt``: `QT Translations TS XML`_ file;
 
-.. versionadded:: 6.1
-
-    The ``.xliff`` file extension support was introduced in Symfony 6.1.
-
 The choice of which loader to use is entirely up to you and is a matter of
 taste. The recommended option is to use YAML for simple projects and use XLIFF
 if you're generating translations with specialized programs or teams.
@@ -598,8 +677,7 @@ Translations of Doctrine Entities
 
 Unlike the contents of templates, it's not practical to translate the contents
 stored in Doctrine Entities using translation catalogs. Instead, use the
-Doctrine `Translatable Extension`_ or the `Translatable Behavior`_. For more
-information, read the documentation of those libraries.
+Doctrine `Translatable Extension`_.
 
 Custom Translation Resources
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -638,10 +716,6 @@ Provider                Install with
 `Phrase`_                ``composer require symfony/phrase-translation-provider``
 ======================  ===========================================================
 
-.. versionadded:: 6.4
-
-    The ``Phrase`` translation provider was introduced in Symfony 6.4.
-
 Each library includes a :ref:`Symfony Flex recipe <symfony-flex>` that will add
 a configuration example to your ``.env`` file. For example, suppose you want to
 use Loco. First, install it:
@@ -805,11 +879,6 @@ now use the following commands to push (upload) and pull (download) translations
     # of flat keys
     $ php bin/console translation:pull loco --force --as-tree
 
-.. versionadded:: 6.4
-
-    The ``--as-tree`` option of the ``translation:pull`` command was introduced
-    in Symfony 6.4.
-
 Creating Custom Providers
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1022,8 +1091,14 @@ preferences. This is achieved with the ``getPreferredLanguage()`` method of the
 
 Symfony finds the best possible language based on the locales passed as argument
 and the value of the ``Accept-Language`` HTTP header. If it can't find a perfect
-match between them, this method returns the first locale passed as argument
-(that's why the order of the passed locales is important).
+match between them, Symfony will try to find a partial match based on the language
+(e.g. ``fr_CA`` would match ``fr_Latn_CH`` because their language is the same).
+If there's no perfect or partial match, this method returns the first locale passed
+as argument (that's why the order of the passed locales is important).
+
+.. versionadded:: 7.1
+
+    The feature to match locales partially was introduced in Symfony 7.1.
 
 .. _translation-fallback:
 
@@ -1101,10 +1176,6 @@ checks translation resources for several locales:
 Switch Locale Programmatically
 ------------------------------
 
-.. versionadded:: 6.1
-
-    The ``LocaleSwitcher`` was introduced in Symfony 6.1.
-
 Sometimes you need to change the application's locale dynamically while running
 some code. For example, a console command that renders email templates in
 different languages. In such cases, you only need to switch the locale temporarily.
@@ -1149,13 +1220,6 @@ The ``LocaleSwitcher`` class allows you to do that::
         }
     }
 
-.. versionadded:: 6.4
-
-    The support of declaring an argument in the callback to inject the locale
-    being used in the
-    :method:`Symfony\\Component\\Translation\\LocaleSwitcher::runWithLocale`
-    method was introduced in Symfony 6.4.
-
 The ``LocaleSwitcher`` class changes the locale of:
 
 * All services tagged with ``kernel.locale_aware``;
@@ -1394,7 +1458,7 @@ Symfony processes all the application translation files as part of the process
 that compiles the application code before executing it. If there's an error in
 any translation file, you'll see an error message explaining the problem.
 
-If you prefer, you can also validate the contents of any YAML and XLIFF
+If you prefer, you can also validate the syntax of any YAML and XLIFF
 translation file using the ``lint:yaml`` and ``lint:xliff`` commands:
 
 .. code-block:: terminal
@@ -1435,6 +1499,22 @@ adapted to the format required by GitHub, but you can force that format too:
 
         $ php vendor/bin/yaml-lint translations/
 
+The ``lint:yaml`` and ``lint:xliff`` commands validate the YAML and XML syntax
+of the translation files, but not their contents. Use the following command
+to check that the translation contents are also correct:
+
+    .. code-block:: terminal
+
+        # checks the contents of all the translation catalogues in all locales
+        $ php bin/console lint:translations
+
+        # checks the contents of the translation catalogues for Italian (it) and Japanese (ja) locales
+        $ php bin/console lint:translations --locale=it --locale=ja
+
+.. versionadded:: 7.2
+
+    The ``lint:translations`` command was introduced in Symfony 7.2.
+
 Pseudo-localization translator
 ------------------------------
 
@@ -1596,7 +1676,6 @@ Learn more
 .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes
 .. _`ISO 639-1`: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
 .. _`Translatable Extension`: https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md
-.. _`Translatable Behavior`: https://github.com/KnpLabs/DoctrineBehaviors
 .. _`Custom Language Name setting`: https://docs.lokalise.com/en/articles/1400492-uploading-files#custom-language-codes
 .. _`ICU resource bundle`: https://github.com/unicode-org/icu-docs/blob/main/design/bnf_rb.txt
 .. _`Portable object format`: https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
diff --git a/validation.rst b/validation.rst
index 79ab57dc8e4..cfa8154b627 100644
--- a/validation.rst
+++ b/validation.rst
@@ -203,10 +203,6 @@ Inside the template, you can output the list of errors exactly as needed:
     object allows you, among other things, to get the constraint that caused this
     violation thanks to the ``ConstraintViolation::getConstraint()`` method.
 
-.. versionadded:: 6.3
-
-    The ``ConstraintViolation::getConstraint()`` method was introduced in Symfony 6.3.
-
 Validation Callables
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -331,99 +327,13 @@ literature genre mostly associated with the author, which can be set to either
             {
                 // ...
 
-                $metadata->addPropertyConstraint('genre', new Assert\Choice([
-                    'choices' => ['fiction', 'non-fiction'],
-                    'message' => 'Choose a valid genre.',
-                ]));
-            }
-        }
-
-.. _validation-default-option:
-
-The options of a constraint can always be passed in as an array. Some constraints,
-however, also allow you to pass the value of one, "*default*", option in place
-of the array. In the case of the ``Choice`` constraint, the ``choices``
-options can be specified in this way.
-
-.. configuration-block::
-
-    .. code-block:: php-attributes
-
-        // src/Entity/Author.php
-        namespace App\Entity;
-
-        // ...
-        use Symfony\Component\Validator\Constraints as Assert;
-
-        class Author
-        {
-            #[Assert\Choice(['fiction', 'non-fiction'])]
-            private string $genre;
-
-            // ...
-        }
-
-    .. code-block:: yaml
-
-        # config/validator/validation.yaml
-        App\Entity\Author:
-            properties:
-                genre:
-                    - Choice: [fiction, non-fiction]
-                # ...
-
-    .. code-block:: xml
-
-        <!-- config/validator/validation.xml -->
-        <?xml version="1.0" encoding="UTF-8" ?>
-        <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
-            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
-                https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
-
-            <class name="App\Entity\Author">
-                <property name="genre">
-                    <constraint name="Choice">
-                        <value>fiction</value>
-                        <value>non-fiction</value>
-                    </constraint>
-                </property>
-
-                <!-- ... -->
-            </class>
-        </constraint-mapping>
-
-    .. code-block:: php
-
-        // src/Entity/Author.php
-        namespace App\Entity;
-
-        // ...
-        use Symfony\Component\Validator\Constraints as Assert;
-        use Symfony\Component\Validator\Mapping\ClassMetadata;
-
-        class Author
-        {
-            private string $genre;
-
-            public static function loadValidatorMetadata(ClassMetadata $metadata): void
-            {
-                // ...
-
-                $metadata->addPropertyConstraint(
-                    'genre',
-                    new Assert\Choice(['fiction', 'non-fiction'])
-                );
+                $metadata->addPropertyConstraint('genre', new Assert\Choice(
+                    choices: ['fiction', 'non-fiction'],
+                    message: 'Choose a valid genre.',
+                ));
             }
         }
 
-This is purely meant to make the configuration of the most common option of
-a constraint shorter and quicker.
-
-If you're ever unsure of how to specify an option, either check the namespace
-``Symfony\Component\Validator\Constraints`` for the constraint or play it safe
-by always passing in an array of options (the first method shown above).
-
 Constraints in Form Classes
 ---------------------------
 
@@ -524,7 +434,7 @@ class to have at least 3 characters.
                 $metadata->addPropertyConstraint('firstName', new Assert\NotBlank());
                 $metadata->addPropertyConstraint(
                     'firstName',
-                    new Assert\Length(['min' => 3])
+                    new Assert\Length(min: 3)
                 );
             }
         }
@@ -607,9 +517,9 @@ this method must return ``true``:
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue([
-                    'message' => 'The password cannot match your first name',
-                ]));
+                $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue(
+                    message: 'The password cannot match your first name',
+                ));
             }
         }
 
diff --git a/validation/custom_constraint.rst b/validation/custom_constraint.rst
index cd5197c860e..10584a36383 100644
--- a/validation/custom_constraint.rst
+++ b/validation/custom_constraint.rst
@@ -39,10 +39,6 @@ First you need to create a Constraint class and extend :class:`Symfony\\Componen
 Add ``#[\Attribute]`` to the constraint class if you want to
 use it as an attribute in other classes.
 
-.. versionadded:: 6.1
-
-    The ``#[HasNamedArguments]`` attribute was introduced in Symfony 6.1.
-
 You can use ``#[HasNamedArguments]`` to make some constraint options required::
 
     // src/Validator/ContainsAlphanumeric.php
@@ -185,10 +181,7 @@ The ``addViolation()`` method call finally adds the violation to the context.
     Validation error messages are automatically translated to the current application
     locale. If your application doesn't use translations, you can disable this behavior
     by calling the ``disableTranslation()`` method of ``ConstraintViolationBuilderInterface``.
-
-    .. versionadded:: 6.4
-
-        The ``disableTranslation()`` method was introduced in Symfony 6.4.
+    See also the :ref:`framework.validation.disable_translation option <reference-validation-disable_translation>`.
 
 Using the new Validator
 -----------------------
@@ -262,7 +255,7 @@ You can use custom validators like the ones provided by Symfony itself:
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
                 $metadata->addPropertyConstraint('name', new NotBlank());
-                $metadata->addPropertyConstraint('name', new ContainsAlphanumeric(['mode' => 'loose']));
+                $metadata->addPropertyConstraint('name', new ContainsAlphanumeric(mode: 'loose'));
             }
         }
 
@@ -287,6 +280,7 @@ define those options as public properties on the constraint class::
     // src/Validator/Foo.php
     namespace App\Validator;
 
+    use Symfony\Component\Validator\Attribute\HasNamedArguments;
     use Symfony\Component\Validator\Constraint;
 
     #[\Attribute]
@@ -296,6 +290,7 @@ define those options as public properties on the constraint class::
         public $message = 'This value is invalid';
         public $optionalBarOption = false;
 
+        #[HasNamedArguments]
         public function __construct(
             $mandatoryFooOption,
             ?string $message = null,
@@ -416,10 +411,10 @@ the custom options like you pass any other option in built-in constraints:
             public static function loadValidatorMetadata(ClassMetadata $metadata)
             {
                 $metadata->addPropertyConstraint('name', new NotBlank());
-                $metadata->addPropertyConstraint('name', new Foo([
-                    'mandatoryFooOption' => 'bar',
-                    'optionalBarOption' => true,
-                ]));
+                $metadata->addPropertyConstraint('name', new Foo(
+                    mandatoryFooOption: 'bar',
+                    optionalBarOption: true,
+                ));
             }
         }
 
@@ -557,6 +552,9 @@ A class constraint validator must be applied to the class itself:
 Testing Custom Constraints
 --------------------------
 
+Atomic Constraints
+~~~~~~~~~~~~~~~~~~
+
 Use the :class:`Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase`
 class to simplify writing unit tests for your custom constraints::
 
@@ -600,3 +598,74 @@ class to simplify writing unit tests for your custom constraints::
             // ...
         }
     }
+
+Compound Constraints
+~~~~~~~~~~~~~~~~~~~~
+
+Consider the following compound constraint that checks if a string meets
+the minimum requirements for your password policy::
+
+    // src/Validator/PasswordRequirements.php
+    namespace App\Validator;
+
+    use Symfony\Component\Validator\Constraints as Assert;
+
+    #[\Attribute]
+    class PasswordRequirements extends Assert\Compound
+    {
+        protected function getConstraints(array $options): array
+        {
+            return [
+                new Assert\NotBlank(allowNull: false),
+                new Assert\Length(min: 8, max: 255),
+                new Assert\NotCompromisedPassword(),
+                new Assert\Type('string'),
+                new Assert\Regex('/[A-Z]+/'),
+            ];
+        }
+    }
+
+You can use the :class:`Symfony\\Component\\Validator\\Test\\CompoundConstraintTestCase`
+class to check precisely which of the constraints failed to pass::
+
+    // tests/Validator/PasswordRequirementsTest.php
+    namespace App\Tests\Validator;
+
+    use App\Validator\PasswordRequirements;
+    use Symfony\Component\Validator\Constraints as Assert;
+    use Symfony\Component\Validator\Test\CompoundConstraintTestCase;
+
+    /**
+     * @extends CompoundConstraintTestCase<PasswordRequirements>
+     */
+    class PasswordRequirementsTest extends CompoundConstraintTestCase
+    {
+        public function createCompound(): Assert\Compound
+        {
+            return new PasswordRequirements();
+        }
+
+        public function testInvalidPassword(): void
+        {
+            $this->validateValue('azerty123');
+
+            // check all constraints pass except for the
+            // password leak and the uppercase letter checks
+            $this->assertViolationsRaisedByCompound([
+                new Assert\NotCompromisedPassword(),
+                new Assert\Regex('/[A-Z]+/'),
+            ]);
+        }
+
+        public function testValid(): void
+        {
+            $this->validateValue('VERYSTR0NGP4$$WORD#%!');
+
+            $this->assertNoViolation();
+        }
+    }
+
+.. versionadded:: 7.2
+
+    The :class:`Symfony\\Component\\Validator\\Test\\CompoundConstraintTestCase`
+    class was introduced in Symfony 7.2.
diff --git a/validation/groups.rst b/validation/groups.rst
index 8d84e52c0da..55625be702d 100644
--- a/validation/groups.rst
+++ b/validation/groups.rst
@@ -101,21 +101,21 @@ user registers and when a user updates their contact information later:
         {
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('email', new Assert\Email([
-                    'groups' => ['registration'],
-                ]));
-
-                $metadata->addPropertyConstraint('password', new Assert\NotBlank([
-                    'groups' => ['registration'],
-                ]));
-                $metadata->addPropertyConstraint('password', new Assert\Length([
-                    'min'    => 7,
-                    'groups' => ['registration'],
-                ]));
-
-                $metadata->addPropertyConstraint('city', new Assert\Length([
-                    'min' => 2,
-                ]));
+                $metadata->addPropertyConstraint('email', new Assert\Email(
+                    groups: ['registration'],
+                ));
+
+                $metadata->addPropertyConstraint('password', new Assert\NotBlank(
+                    groups: ['registration'],
+                ));
+                $metadata->addPropertyConstraint('password', new Assert\Length(
+                    min: 7,
+                    groups: ['registration'],
+                ));
+
+                $metadata->addPropertyConstraint('city', new Assert\Length(
+                    min: 2,
+                ));
             }
         }
 
diff --git a/validation/sequence_provider.rst b/validation/sequence_provider.rst
index 836568c2327..c316a85d249 100644
--- a/validation/sequence_provider.rst
+++ b/validation/sequence_provider.rst
@@ -104,10 +104,10 @@ username and the password are different only if all other validation passes
                 $metadata->addPropertyConstraint('username', new Assert\NotBlank());
                 $metadata->addPropertyConstraint('password', new Assert\NotBlank());
 
-                $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue([
-                    'message' => 'The password cannot match your first name',
-                    'groups'  => ['Strict'],
-                ]));
+                $metadata->addGetterConstraint('passwordSafe', new Assert\IsTrue(
+                    message: 'The password cannot match your first name',
+                    groups: ['Strict'],
+                ));
 
                 $metadata->setGroupSequence(['User', 'Strict']);
             }
@@ -249,10 +249,10 @@ entity and a new constraint group called ``Premium``:
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
                 $metadata->addPropertyConstraint('name', new Assert\NotBlank());
-                $metadata->addPropertyConstraint('creditCard', new Assert\CardScheme([
-                    'schemes' => [Assert\CardScheme::VISA],
-                    'groups'  => ['Premium'],
-                ]));
+                $metadata->addPropertyConstraint('creditCard', new Assert\CardScheme(
+                    schemes: [Assert\CardScheme::VISA],
+                    groups: ['Premium'],
+                ));
             }
         }
 
diff --git a/validation/severity.rst b/validation/severity.rst
index 632a99519d9..154c13d5e3e 100644
--- a/validation/severity.rst
+++ b/validation/severity.rst
@@ -105,15 +105,15 @@ Use the ``payload`` option to configure the error level for each constraint:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('username', new Assert\NotBlank([
-                    'payload' => ['severity' => 'error'],
-                ]));
-                $metadata->addPropertyConstraint('password', new Assert\NotBlank([
-                    'payload' => ['severity' => 'error'],
-                ]));
-                $metadata->addPropertyConstraint('bankAccountNumber', new Assert\Iban([
-                    'payload' => ['severity' => 'warning'],
-                ]));
+                $metadata->addPropertyConstraint('username', new Assert\NotBlank(
+                    payload: ['severity' => 'error'],
+                ));
+                $metadata->addPropertyConstraint('password', new Assert\NotBlank(
+                    payload: ['severity' => 'error'],
+                ));
+                $metadata->addPropertyConstraint('bankAccountNumber', new Assert\Iban(
+                    payload: ['severity' => 'warning'],
+                ));
             }
         }
 
diff --git a/validation/translations.rst b/validation/translations.rst
index 9a4ece17736..db2cd518eb7 100644
--- a/validation/translations.rst
+++ b/validation/translations.rst
@@ -83,9 +83,9 @@ property is not empty, add the following:
 
             public static function loadValidatorMetadata(ClassMetadata $metadata): void
             {
-                $metadata->addPropertyConstraint('name', new NotBlank([
-                    'message' => 'author.name.not_blank',
-                ]));
+                $metadata->addPropertyConstraint('name', new NotBlank(
+                    message: 'author.name.not_blank',
+                ));
             }
         }
 
@@ -136,13 +136,13 @@ You can also use :class:`Symfony\\Component\\Translation\\TranslatableMessage` t
     use Symfony\Component\Translation\TranslatableMessage;
     use Symfony\Component\Validator\Constraints as Assert;
     use Symfony\Component\Validator\Context\ExecutionContextInterface;
-    
+
     #[Assert\Callback]
     public function validate(ExecutionContextInterface $context, mixed $payload): void
     {
         // somehow you have an array of "fake names"
         $fakeNames = [/* ... */];
-    
+
         // check if the name is actually a fake name
         if (in_array($this->getFirstName(), $fakeNames, true)) {
             $context->buildViolation(new TranslatableMessage('author.name.fake', [], 'validators'))
diff --git a/webhook.rst b/webhook.rst
index be4ccbcf95d..d27a6e6d906 100644
--- a/webhook.rst
+++ b/webhook.rst
@@ -1,10 +1,6 @@
 Webhook
 =======
 
-.. versionadded:: 6.3
-
-    The Webhook component was introduced in Symfony 6.3.
-
 The Webhook component is used to respond to remote webhooks to trigger actions
 in your application. This document focuses on using webhooks to listen to remote
 events in other Symfony components.
@@ -19,24 +15,45 @@ Installation
 Usage in Combination with the Mailer Component
 ----------------------------------------------
 
+.. admonition:: Screencast
+    :class: screencast
+
+    Like video tutorials? Check out the `Webhook Component for Email Events screencast`_.
+
 When using a third-party mailer provider, you can use the Webhook component to
 receive webhook calls from this provider.
 
 Currently, the following third-party mailer providers support webhooks:
 
-============== ==========================================
+============== ============================================
 Mailer Service Parser service name
-============== ==========================================
+============== ============================================
+AhaSend        ``mailer.webhook.request_parser.ahasend``
 Brevo          ``mailer.webhook.request_parser.brevo``
+Mandrill       ``mailer.webhook.request_parser.mailchimp``
+MailerSend     ``mailer.webhook.request_parser.mailersend``
 Mailgun        ``mailer.webhook.request_parser.mailgun``
 Mailjet        ``mailer.webhook.request_parser.mailjet``
+Mailomat       ``mailer.webhook.request_parser.mailomat``
+Mailtrap       ``mailer.webhook.request_parser.mailtrap``
 Postmark       ``mailer.webhook.request_parser.postmark``
+Resend         ``mailer.webhook.request_parser.resend``
 Sendgrid       ``mailer.webhook.request_parser.sendgrid``
-============== ==========================================
+Sweego         ``mailer.webhook.request_parser.sweego``
+============== ============================================
+
+.. versionadded:: 7.1
+
+    The support for ``Resend`` and ``MailerSend`` were introduced in Symfony 7.1.
+
+.. versionadded:: 7.2
+
+    The ``Mandrill``, ``Mailomat``, ``Mailtrap``, and ``Sweego`` integrations were introduced in
+    Symfony 7.2.
 
-.. versionadded:: 6.4
+.. versionadded:: 7.3
 
-    The support for Brevo, Mailjet and Sendgrid was introduced in Symfony 6.4.
+    The ``AhaSend`` integration was introduced in Symfony 7.3.
 
 .. note::
 
@@ -159,6 +176,8 @@ Currently, the following third-party SMS transports support webhooks:
 SMS service  Parser service name
 ============ ==========================================
 Twilio       ``notifier.webhook.request_parser.twilio``
+Smsbox       ``notifier.webhook.request_parser.smsbox``
+Sweego       ``notifier.webhook.request_parser.sweego``
 Vonage       ``notifier.webhook.request_parser.vonage``
 ============ ==========================================
 
@@ -199,3 +218,4 @@ Creating a Custom Webhook
     Webhook.
 
 .. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html
+.. _`Webhook Component for Email Events screencast`: https://symfonycasts.com/screencast/mailtrap/email-event-webhook
diff --git a/workflow.rst b/workflow.rst
index 45e9a41b75b..54a1b06313e 100644
--- a/workflow.rst
+++ b/workflow.rst
@@ -60,7 +60,7 @@ follows:
                     supports:
                         - App\Entity\BlogPost
                     initial_marking: draft
-                    places:
+                    places:          # defining places manually is optional
                         - draft
                         - reviewed
                         - rejected
@@ -97,10 +97,13 @@ follows:
                     </framework:marking-store>
                     <framework:support>App\Entity\BlogPost</framework:support>
                     <framework:initial-marking>draft</framework:initial-marking>
+
+                    <!-- defining places manually is optional -->
                     <framework:place>draft</framework:place>
                     <framework:place>reviewed</framework:place>
                     <framework:place>rejected</framework:place>
                     <framework:place>published</framework:place>
+
                     <framework:transition name="to_review">
                         <framework:from>draft</framework:from>
                         <framework:to>reviewed</framework:to>
@@ -135,6 +138,7 @@ follows:
                 ->type('method')
                 ->property('currentPlace');
 
+            // defining places manually is optional
             $blogPublishing->place()->name('draft');
             $blogPublishing->place()->name('reviewed');
             $blogPublishing->place()->name('rejected');
@@ -168,10 +172,16 @@ follows:
     ``'draft'`` or ``!php/const App\Entity\BlogPost::TRANSITION_TO_REVIEW``
     instead of ``'to_review'``.
 
-.. versionadded:: 6.4
+.. tip::
+
+    You can omit the ``places`` option if your transitions define all the places
+    that are used in the workflow. Symfony will automatically extract the places
+    from the transitions.
+
+    .. versionadded:: 7.1
 
-    Since Symfony 6.4, the ``type`` option under ``marking_store`` can be
-    omitted when the ``property`` option is explicitly set.
+        The support for omitting the ``places`` option was introduced in
+        Symfony 7.1.
 
 The configured property will be used via its implemented getter/setter methods by the marking store::
 
@@ -231,11 +241,6 @@ you must declare a setter to write your property::
         }
     }
 
-.. versionadded:: 6.4
-
-    The feature to use public properties instead of getter/setter methods
-    and private properties was introduced in Symfony 6.4.
-
 .. note::
 
     The marking store type could be "multiple_state" or "single_state". A single
@@ -355,6 +360,15 @@ machine type, use ``camelCased workflow name + StateMachine``::
         }
     }
 
+To get the enabled transition of a Workflow, you can use
+:method:`Symfony\\Component\\Workflow\\WorkflowInterface::getEnabledTransition`
+method.
+
+.. versionadded:: 7.1
+
+    The :method:`Symfony\\Component\\Workflow\\WorkflowInterface::getEnabledTransition`
+    method was introduced in Symfony 7.1.
+
 Workflows can also be injected thanks to their name and the
 :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Target`
 attribute::
@@ -377,16 +391,6 @@ attribute::
 This allows you to decorrelate the argument name of any implementation
 name.
 
-.. versionadded:: 6.2
-
-    All workflows and state machines services are tagged since in Symfony 6.2.
-
-.. versionadded:: 6.3
-
-    Injecting a workflow with only its name and
-    :class:`Symfony\\Component\\DependencyInjection\\Attribute\\Target` was
-    introduced in Symfony 6.3.
-
 .. tip::
 
     If you want to retrieve all workflows, for documentation purposes for example,
@@ -397,6 +401,15 @@ name.
     * ``workflow.workflow``: all workflows;
     * ``workflow.state_machine``: all state machines.
 
+    Note that workflow metadata are attached to tags under the ``metadata`` key,
+    giving you more context and information about the workflow at disposal.
+    Learn more about :ref:`tag attributes <tags_additional-attributes>` and
+    :ref:`storing workflow metadata <workflow_storing-metadata>`.
+
+    .. versionadded:: 7.1
+
+        The attached configuration to the tag was introduced in Symfony 7.1.
+
 .. tip::
 
     You can find the list of available workflow services with the
@@ -498,21 +511,6 @@ order:
 
         $workflow->apply($subject, $transitionName, [Workflow::DISABLE_ANNOUNCE_EVENT => true]);
 
-The context is accessible in all events except for the ``workflow.guard`` events::
-
-    // $context must be an array
-    $context = ['context_key' => 'context_value'];
-    $workflow->apply($subject, $transitionName, $context);
-
-    // in an event listener (workflow.guard events)
-    $context = $event->getContext(); // returns ['context']
-
-.. deprecated:: 6.4
-
-    Gathering events context is deprecated since Symfony 6.4 and the
-    :method:`Symfony\\Component\\Workflow\\Event\\Event::getContext` method will be
-    removed in Symfony 7.0.
-
 .. note::
 
     The leaving and entering events are triggered even for transitions that stay
@@ -533,6 +531,7 @@ workflow leaves a place::
     use Psr\Log\LoggerInterface;
     use Symfony\Component\EventDispatcher\EventSubscriberInterface;
     use Symfony\Component\Workflow\Event\Event;
+    use Symfony\Component\Workflow\Event\LeaveEvent;
 
     class WorkflowLoggerSubscriber implements EventSubscriberInterface
     {
@@ -555,11 +554,24 @@ workflow leaves a place::
         public static function getSubscribedEvents(): array
         {
             return [
-                'workflow.blog_publishing.leave' => 'onLeave',
+                LeaveEvent::getName('blog_publishing') => 'onLeave',
+                // if you prefer, you can write the event name manually like this:
+                // 'workflow.blog_publishing.leave' => 'onLeave',
             ];
         }
     }
 
+.. tip::
+
+    All built-in workflow events define the ``getName(?string $workflowName, ?string $transitionOrPlaceName)``
+    method to build the full event name without having to deal with strings.
+    You can also use this method in your custom events via the
+    :class:`Symfony\\Component\\Workflow\\Event\\EventNameTrait`.
+
+    .. versionadded:: 7.1
+
+        The ``getName()`` method was introduced in Symfony 7.1.
+
 If some listeners update the context during a transition, you can retrieve
 it via the marking::
 
@@ -598,10 +610,6 @@ You may refer to the documentation about
 :ref:`defining event listeners with PHP attributes <event-dispatcher_event-listener-attributes>`
 for further use.
 
-.. versionadded:: 6.4
-
-    The workflow event attributes were introduced in Symfony 6.4.
-
 .. _workflow-usage-guard-events:
 
 Guard Events
@@ -1088,6 +1096,8 @@ The following example shows these functions in action:
         <span class="error">{{ blocker.message }}</span>
     {% endfor %}
 
+.. _workflow_storing-metadata:
+
 Storing Metadata
 ----------------
 
@@ -1296,6 +1306,87 @@ In Twig templates, metadata is available via the ``workflow_metadata()`` functio
         </ul>
     </p>
 
+Validating Workflow Definitions
+-------------------------------
+
+Symfony allows you to validate workflow definitions using your own custom logic.
+To do so, create a class that implements the
+:class:`Symfony\\Component\\Workflow\\Validator\\DefinitionValidatorInterface`::
+
+    namespace App\Workflow\Validator;
+
+    use Symfony\Component\Workflow\Definition;
+    use Symfony\Component\Workflow\Exception\InvalidDefinitionException;
+    use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface;
+
+    final class BlogPublishingValidator implements DefinitionValidatorInterface
+    {
+        public function validate(Definition $definition, string $name): void
+        {
+            if (!$definition->getMetadataStore()->getMetadata('title')) {
+                throw new InvalidDefinitionException(sprintf('The workflow metadata title is missing in Workflow "%s".', $name));
+            }
+
+            // ...
+        }
+    }
+
+After implementing your validator, configure your workflow to use it:
+
+.. configuration-block::
+
+    .. code-block:: yaml
+
+        # config/packages/workflow.yaml
+        framework:
+            workflows:
+                blog_publishing:
+                    # ...
+
+                    definition_validators:
+                        - App\Workflow\Validator\BlogPublishingValidator
+
+    .. code-block:: xml
+
+        <!-- config/packages/workflow.xml -->
+        <?xml version="1.0" encoding="UTF-8" ?>
+        <container xmlns="http://symfony.com/schema/dic/services"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xmlns:framework="http://symfony.com/schema/dic/symfony"
+            xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd
+                http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
+        >
+            <framework:config>
+                <framework:workflow name="blog_publishing">
+                    <!-- ... -->
+                    <framework:definition-validators>App\Workflow\Validator\BlogPublishingValidator</framework:definition-validators>
+                </framework:workflow>
+            </framework:config>
+        </container>
+
+    .. code-block:: php
+
+        // config/packages/workflow.php
+        use Symfony\Config\FrameworkConfig;
+
+        return static function (FrameworkConfig $framework): void {
+            $blogPublishing = $framework->workflows()->workflows('blog_publishing');
+            // ...
+
+            $blogPublishing->definitionValidators([
+                App\Workflow\Validator\BlogPublishingValidator::class
+            ]);
+
+            // ...
+        };
+
+The ``BlogPublishingValidator`` will be executed during container compilation
+to validate the workflow definition.
+
+.. versionadded:: 7.3
+
+    Support for workflow definition validators was introduced in Symfony 7.3.
+
 Learn more
 ----------
 
diff --git a/workflow/dumping-workflows.rst b/workflow/dumping-workflows.rst
index d31b1eb15a8..8262fefd6c1 100644
--- a/workflow/dumping-workflows.rst
+++ b/workflow/dumping-workflows.rst
@@ -80,10 +80,6 @@ The DOT image will look like this :
 
     The ``label`` metadata is not included in the dumped metadata, because it is used as a place's title.
 
-.. versionadded:: 6.4
-
-    The ``--with-metadata`` option was introduced in Symfony 6.4.
-
 You can use ``metadata`` with the following keys to style the workflow:
 
 * for places:
diff --git a/workflow/workflow-and-state-machine.rst b/workflow/workflow-and-state-machine.rst
index b77282cca21..3a034b97357 100644
--- a/workflow/workflow-and-state-machine.rst
+++ b/workflow/workflow-and-state-machine.rst
@@ -252,6 +252,17 @@ Below is the configuration for the pull request state machine.
                     ->to(['review']);
         };
 
+.. tip::
+
+    You can omit the ``places`` option if your transitions define all the places
+    that are used in the workflow. Symfony will automatically extract the places
+    from the transitions.
+
+    .. versionadded:: 7.1
+
+        The support for omitting the ``places`` option was introduced in
+        Symfony 7.1.
+
 Symfony automatically creates a service for each workflow (:class:`Symfony\\Component\\Workflow\\Workflow`)
 or state machine (:class:`Symfony\\Component\\Workflow\\StateMachine`) you
 have defined in your configuration. You can use the workflow inside a class by using
@@ -282,10 +293,6 @@ machine type, use ``camelCased workflow name + StateMachine``::
         // ...
     }
 
-.. versionadded:: 6.2
-
-    All workflows and state machines services are tagged since in Symfony 6.2.
-
 Automatic and Manual Validation
 -------------------------------
 
