Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll
13/04/2025, by Ivan

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.