Skip to content

Config Override System

When to Use

When you need to override config values per environment (e.g., API keys, site name) without modifying stored config or committing credentials to Git.

Override Layers

Drupal applies overrides in this order (later overrides win): 1. Active storage — Database config (base values) 2. Module overrides — Via ConfigFactoryOverrideInterface services 3. Settings overrides$config array in settings.php

Decision

If you need... Use... Why
Environment-specific values settings.php overrides Per-environment, not in Git (gitignored settings.local.php)
Dynamic overrides Module overrides via service Conditional logic, depend on runtime state
Language-specific config Language module overrides Automatic per-language config translation
Temporary testing settings.php overrides Quick, no code deployment
Complex conditional logic Module override service Full access to container, state, request

Example: Settings.php Overrides

// settings.php or settings.local.php
$config['system.site']['name'] = 'Dev Site';
$config['system.site']['mail'] = 'dev@example.com';

// Override nested values
$config['mymodule.settings']['api']['key'] = 'dev-api-key-123';
$config['mymodule.settings']['api']['endpoint'] = 'https://dev-api.example.com';

// Override config entity (use full name with ID)
$config['node.type.article']['name'] = 'Dev Article';

// Per-environment example
if (getenv('ENVIRONMENT') === 'production') {
  $config['system.performance']['cache']['page']['max_age'] = 3600;
  $config['system.logging']['error_level'] = 'hide';
}
else {
  $config['system.performance']['cache']['page']['max_age'] = 0;
  $config['system.logging']['error_level'] = 'verbose';
}

Reference: /core/lib/Drupal/Core/Config/Config.php lines 144-163 (setOverriddenData)

Example: Module Override Service

// mymodule/src/Config/MyModuleConfigOverrides.php
namespace Drupal\mymodule\Config;

use Drupal\Core\Config\ConfigFactoryOverrideInterface;
use Drupal\Core\Config\StorageInterface;

class MyModuleConfigOverrides implements ConfigFactoryOverrideInterface {

  public function loadOverrides($names) {
    $overrides = [];

    if (in_array('system.site', $names)) {
      // Conditional override based on runtime state
      if ($this->isMaintenanceMode()) {
        $overrides['system.site']['name'] = 'Site Under Maintenance';
      }
    }

    return $overrides;
  }

  public function getCacheSuffix() {
    return 'MyModuleConfigOverride';
  }

  public function getCacheableMetadata($name) {
    return new CacheableMetadata();
  }

  public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) {
    return NULL;
  }
}

Service definition:

# mymodule.services.yml
services:
  mymodule.config_overrides:
    class: Drupal\mymodule\Config\MyModuleConfigOverrides
    tags:
      - { name: config.factory.override, priority: 5 }

Reference: /core/lib/Drupal/Core/Config/ConfigFactoryOverrideInterface.php, /core/modules/language/src/Config/LanguageConfigOverride.php

Override Priority

Lower priority values run first, higher values run last and win conflicts: - Priority -100: Low priority, runs early - Priority 0: Default - Priority 5: Module overrides (typical) - Priority 100: settings.php overrides (highest, always wins)

Checking for Overrides

$config = \Drupal::config('system.site');

// Check if any overrides exist
if ($config->hasOverrides()) {
  // Get current value (with overrides)
  $name = $config->get('name');

  // Get original value (without overrides)
  $original_name = $config->getOriginal('name', FALSE);

  // Check specific key
  if ($config->hasOverrides('name')) {
    // 'name' key is overridden
  }
}

// Get editable config (no overrides)
$editable = \Drupal::service('config.factory')->getEditable('system.site');
$stored_name = $editable->get('name'); // Always returns stored value

Common Mistakes

  • Storing overrides in settings.php committed to Git — Use gitignored settings.local.php
  • Overriding config entities without full name — Must include entity ID (e.g., node.type.article)
  • Editing config that has overrides — Changes saved but overridden at runtime
  • Not checking for overrides before comparing — Comparing overridden vs stored values
  • Using overrides for permanent changes — Overrides are runtime-only, export/import uses stored values
  • High-priority module overrides conflicting — Lower priority value, or use settings.php

See Also