Configuration Override system
Drupal 8's configuration system handles configuration in a unified way. By default, Drupal stores configuration data in the database, but it can be exported to YAML files for version control. However, there are scenarios where configuration values need to be overridden for specific purposes. In Drupal 7, this was done using the global $conf variable, often populated in settings.php for conditional overrides. A major drawback of that system was that overrides would be saved into the actual configuration storage. When a configuration form containing overridden values was saved, the override would be persisted.
Drupal 8 introduces a configuration override system that:
- Supports these overrides as temporary layers on top of standard configuration values
- Does not use overridden values in configuration forms
- Can store overrides with other configuration files to support staging and version control (e.g., language overrides; see below)
The global $conf variable in Drupal 7 is renamed to $config in Drupal 8 and is activated in the configuration system by default.
Global Overrides
Drupal 8 retains the ability to use global $config. The configuration system merges override values through the implementation of Drupal\Core\Config\ConfigFactory::get()
. When retrieving a configuration value, the global $config variable gets a chance to alter the returned value:
// Get the maintenance mode message. This value may be overridden by global $config. $message = \Drupal::config('system.maintenance')->get('message');
To override configuration values globally, for instance in settings.php
:
$config['system.maintenance']['message'] = 'Sorry, our site is down now.';
For nested values, use nested array keys:
$config['system.performance']['css']['preprocess'] = 0;
Outside of settings.php, use the global $config variable from the service container.
You can inspect available config keys using:
- The “Configuration Manager” module at
/admin/config/development/configuration/single/export
- Directly inspecting your site’s YAML config files
- Or using Drush commands:
drush config-list drush config-get system.performance --include-overridden
Note: Overrides via $config in settings.php are not visible in the Drupal admin UI or via Drush unless using --include-overridden
. To highlight overridden values in forms, consider modules like Configuration Override Warn or Config Override Inspector.
Avoiding Overrides
You can get config values without overrides using getOriginal()
. This is especially useful when writing configuration forms to avoid persisting overridden values:
// With overrides $site_name = \Drupal::config('system.site')->get('name'); // Without overrides $site_name = \Drupal::config('system.site')->getOriginal('name', FALSE); // Editable config is always override-free $site_name = \Drupal::configFactory()->getEditable('system.site')->get('name');
You may also access raw config storage via the config.storage
service (implements StorageInterface::read()
), though this is rarely recommended.
Language Overrides
For language-specific scenarios (e.g., sending emails in a user’s preferred language), use the following pattern:
$language_manager = \Drupal::service('language_manager'); $langcode = $account->getPreferredLangcode(); $language = $language_manager->getLanguage($langcode); $original_language = $language_manager->getConfigOverrideLanguage(); $language_manager->setConfigOverrideLanguage($language); $mail_config = \Drupal::config('user.mail'); // Send localized email using $mail_config $language_manager->setConfigOverrideLanguage($original_language);
Language overrides are stored in config files named like language.config.$langcode.user.mail
and handled similarly to regular config files, enabling export and staging.
These files are generated through integration with the locale module and core’s configuration translation module, which provide UI for translating both shipped and custom configuration.
Providing Overrides via Modules
Modules can provide their own override logic, tagged as config.factory.override
in their service definitions:
# config_example.services.yml services: config_example.overrider: class: Drupal\config_example\Config\ConfigExampleOverrides tags: - {name: config.factory.override, priority: 5}
Example override implementation:
namespace Drupal\config_example\Config; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Config\ConfigFactoryOverrideInterface; use Drupal\Core\Config\StorageInterface; class ConfigExampleOverrides implements ConfigFactoryOverrideInterface { public function loadOverrides($names) { $overrides = []; if (in_array('system.site', $names)) { $overrides['system.site'] = ['name' => 'Overridden site name!']; } return $overrides; } public function getCacheSuffix() { return 'ConfigExampleOverrider'; } public function getCacheableMetadata($name) { return new CacheableMetadata(); } public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) { return NULL; } }
There are three override levels: language, modules, and settings.php. settings.php takes precedence over module overrides, which take precedence over language overrides.
Note: Core config forms do not use overridden values. In the example above, you won’t see “Overridden site name!” at /admin/config/system/site-information
.
// Read original config in an override implementation $original = \Drupal::configFactory()->getEditable('system.site')->getOriginal('name', FALSE);
Additional References
Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.