The state service / \Drupal\Core\State\State extends \Drupal\Core\Cache\CacheCollector. This results in fewer queries to the database because a single cache entry stores commonly accessed state items.
Most code will not need to make any changes. Note that this feature currently needs to be enabled on sites with an existing settings.php file; for more information, see the section "Opt-in/out".
Recommended usage of the state API
The state API should be used primarily for frequently accessed and relatively small pieces of data that may or may not change frequently that aren't managed through configuration (typically because they are automatically generated/updated and not meant to be synchronized between environments).
Good examples in Drupal core include the maintenance flag, the private key, last cron execution, data for optimizing route lookups, and similar cases.
An example of non-optimal usage of the state API is the new development flag, which is only accessed through a container rebuild. See #3437162: Move twig_debug and other development toggles into raw key/value.
Modules that wish to maintain many larger or infrequently accessed pieces of data can use the key value API with a different collection, for example.
Opt-in/out
To prevent issues with existing sites that may have many or large state entries, this feature needs to be enabled explicitly through the settings flag $settings['state_cache'] = TRUE;. This is the default behavior in default.settings.php, which is used as a template when no settings.php exists yet for a new site.
If the settings flag is not explicitly set to either TRUE (enabled) or FALSE (disabled), a requirements warning message will be shown, recommending what explicit value should be set. In Drupal 11+, settings 'state_cache' is removed and permanently turned on.
To check current state usage, check the number of state entries in the default database backend using the following query:
> SELECT COUNT(*), SUM(LENGTH(value)) FROM key_value WHERE collection = 'state';
+----------+--------------------+
| COUNT(*) | SUM(LENGTH(value)) |
+----------+--------------------+
| 19 | 22016 |
+----------+--------------------+
Sites with more than 100 entries and/or a total value size/length of 100,000 should review their specific entries using the following query and either optimize their usage or disable state caching as a temporary measure:
> SELECT name, LENGTH(value) FROM key_value WHERE collection = 'state' ORDER BY LENGTH(value) DESC LIMIT 100;
+----------------------------------------+---------------+
| name | LENGTH(value) |
+----------------------------------------+---------------+
| system.javascript_parsed | 9530 |
| routing.non_admin_routes | 6178 |
| system.profile.files | 1817 |
| views.view_route_names | 1490 |
| router.path_roots | 1099 |
| system.theme.files | 769 |
| routing.menu_masks.router | 750 |
| twig_extension_hash_prefix | 130 |
....
Possible impacts
In order to facilitate this change, the constructor for \Drupal\Core\State\State::__construct now requires a cache backend and the lock service to be injected. Support for calling this without those services is removed in Drupal 11.
Drupal\Core\Routing\RoutePreloader previously cached the routes internally; now that the state items are cached directly, this cache layer has been removed. If you were using the RoutePreloader, you no longer need to pass a cache bin to the constructor.
It is no longer necessary to wrap state data in a cache; an additional example in Drupal core for this that was updated is ExtensionList::getPathNames(). It is recommended to adjust code that is wrapping state data in a cache and remove the extra caching layers.