Config as Single Source of Truth
When to Use
Whenever you need to store site settings, entity definitions, field configurations, view definitions, or any setting that should be consistent across environments.
Decision
| If you need... | Use... | Why |
|---|---|---|
| Site name, slogan, email | system.site config |
Already exists, UI-editable, version-controlled |
| Module settings, API keys | Custom config entity (mymodule.settings) |
Exportable, overridable per environment |
| Field definitions, entity types | Config entities via UI or install config | Schema-driven, validated, portable |
| Different values per environment (dev/prod) | Config overrides in settings.php or Config Split | Environment-specific without code changes |
| Never store in code | Nothing — read from config | Config is the source of truth |
Pattern
# config/install/mymodule.settings.yml
api:
endpoint: 'https://api.example.com'
timeout: 30
cache:
enabled: true
ttl: 3600
// Read config (never duplicate values)
$config = $this->configFactory->get('mymodule.settings');
$endpoint = $config->get('api.endpoint');
$timeout = $config->get('api.timeout');
// WRONG: Duplicating config in code
const API_ENDPOINT = 'https://api.example.com'; // Don't do this
// Write config (only in install/update hooks or admin forms)
$config = $this->configFactory->getEditable('mymodule.settings');
$config->set('api.endpoint', $form_state->getValue('endpoint'))->save();
Reference: core/lib/Drupal/Core/Config/ConfigFactoryInterface.php, core/modules/system/config/install/system.site.yml
Workflow for Config Changes
- Make change on local — Update via UI or modify YAML in
config/sync/ - Export config —
drush config:export(ordrush cex) - Commit to version control — Config files in
config/sync/directory - Deploy to other environments — Pull code, run
drush config:import(ordrush cim) - Verify — Check that changes applied correctly
This workflow ensures config is the single source of truth across all environments.
Common Mistakes
- Hardcoding values that belong in config — Use config, not constants or hardcoded strings
- Storing config in code variables — Read dynamically from config, don't cache in class properties
- Not exporting config after changes — Changes via UI won't deploy unless exported
- Mixing config and content — Content entities (nodes, users) are not config; config entities (views, field definitions) are config
- Ignoring config schema — Define schema in
mymodule.schema.ymlfor validation and IDE support