Synchronizing Drupal Configuration Across Environments Using Config Management
Learn how to keep Drupal configuration in sync across dev, stage, and prod using config management, drush, and optional config splits.
29 Jun 2026, 06:41 UTC

Desired outcome
Keep site configuration identical across development, staging, and production environments while allowing environment‑specific overrides (e.g., debug mode, API keys) without manual copy‑pasting.
Prerequisites
- Drupal 8, 9, or 10 installed on each target environment.
- Drush 10+ available and configured to point to the Drupal root of each environment.
- Git (or another VCS) repository initialized with the project code.
- File system permissions that allow the web‑server user (commonly
www-dataorapache) to read and write the configuration sync directory. - The
config_splitmodule installed and enabled if you need environment‑specific splits.
Step‑by‑step procedure
- Choose a sync directory
In
settings.php(orsettings.local.php) set:$settings['config_sync_directory'] = '../config/sync';Place the directory outside the web root but within the project repository so it can be version‑controlled.
- Export configuration from the source environment (e.g., development)
Run:
drush config:export -y --destination=../config/syncThis writes YAML files representing the active configuration to the sync directory.
- Commit the exported config
Add, commit, and push the changes:
git add config/sync git commit -m "Export configuration from dev (YYYY‑MM‑DD)" git push origin main - Pull the config on the target environment (e.g., staging)
On the staging server:
git pull origin main drush config:import -y --source=../config/syncDrush will compare the active config with the YAML files and apply any differences.
- Handle environment‑specific splits (optional)
If you use
config_splitto exclude debug settings or API keys:- Create a split (e.g.,
dev) via the UI atadmin/config/development/config_split. - Export the split configuration:
drush config:export -y --destination=../config/split/dev - Add the split directory to
.gitignoreso the actual split files are not committed, but keep the split definition (theconfig_split.config_split.*YAML) in sync. - On each environment, enable the appropriate split:
drush config-set config_split.split.dev status 0 -y # disable on production drush config-set config_split.split.dev status 1 -y # enable on dev/staging
- Create a split (e.g.,
Expected checks
- List pending changes before importing:
drush config:statusThe output should show no "pending" items if the export and import are in sync.
- Clear caches after import to ensure new config is active:
drush cr - Verify a specific setting (e.g., site name) via Drush:
drush cget system.site nameCompare the output with the value in the YAML file.
- Check logs and status report for configuration errors:
- Watchdog:
drush watchdog:show --type="php" --limit=10 - Status report: visit
admin/reports/statusor rundrush statusand look for the "Configuration system" section.
- Watchdog:
Recovery / rollback options
Because config:import changes the active configuration, you can revert to a known good state:
- Reset the Git branch to the commit before the unwanted export:
git reset --hard git push --force origin main # use with caution - Re‑export the configuration from the reset state and import it on the target environment:
drush config:export -y --destination=../config/sync drush config:import -y --source=../config/sync drush cr - If only a few items are wrong, you can re‑import a single configuration object:
drush config:import --partial --source=../config/sync system.site
Limitations and practical tips
- Configuration UUIDs must match across environments; moving config between sites with different UUIDs will cause import failures. Always export/import from the same site clone or use
drush config:editto correct UUIDs only when you understand the impact. - The
config_splitmodule does not automatically keep split files out of the sync directory; you must manually add the split folder to.gitignore. - Large numbers of configuration items can make
drush config:statusslow; consider filtering withdrush config:status --list-onlyor checking specific modules. - Never edit configuration directly in the database on a live site; changes made there will be lost on the next import.
- After any import, always clear caches (
drush cr) and verify the site behaves as expected before declaring the operation successful.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.