Stop Losing Drupal Configuration Between Environments: A Practical Git Workflow
Drupal configuration lives in the database until you export it. Learn how to move views, content types, and menus between environments using YAML and Drush without losing changes.
30 May 2026, 23:01 UTC

The Problem: Configuration Changes That Vanish
You tweak a view on staging, add a field to a content type on production, and adjust a menu on your local machine. None of those changes exist in your Git repository. Drupal stores most site structure in database tables, which means your carefully adjusted settings are invisible to version control until you explicitly export them.
The useful takeaway: Drupal's Configuration Management system turns site structure into YAML files. Once those files live in Git, configuration becomes reviewable, portable, and deployable like any other code artifact.
What Configuration Management Actually Exports
Configuration entities are the structured objects that define how your site behaves: content types, field definitions, views, menus, image styles, text formats, and taxonomy vocabularies. When you run an export, Drupal serializes these entities into individual YAML files inside a configuration sync directory. That directory path is defined in your settings.php file, commonly via $settings['config_sync_directory'], and is often placed outside the webroot for security.
What does not get exported? Content nodes, user accounts, sessions, logs, and cache data. Configuration management handles the blueprint, not the building materials.
The Export-Import Cycle with Drush
Drush provides the command-line interface for moving configuration between environments. The core commands are config:export, config:import, and config:diff. These apply to Drupal 8 and later with Drush 10 or newer; always confirm syntax against your installed version.
Exporting happens on the source environment—typically your local machine. Run drush config:export from the Drupal project root. This requires filesystem write access to the sync directory. The expected result is a set of new or modified YAML files in that directory. Review them with git diff before committing.
Importing happens on the target environment, such as staging or production. Run drush config:import from the project root. This requires database write permissions and is best performed during a maintenance window or with the site in maintenance mode, because active configuration changes immediately. The operation is idempotent: if the source YAML matches what is already active, repeated imports will not duplicate entities or create conflicts, provided the source state is consistent.
Diffing is your safety check. Run drush config:diff from the project root on any environment to compare active database configuration against the YAML files in the sync directory. It is read-only and requires no special permissions beyond reading the filesystem and database.
Worked Example: Moving a New Field to Production
Suppose you need to add a subtitle field to the Article content type. You make the change through the Drupal admin UI on your local environment. The field now exists in your local database, but nowhere else.
On your local machine, from the project root, run:
drush config:export
This writes YAML files for the field storage, form display, and view display into your sync directory. Inspect the changes:
git diff path/to/config_sync_directory
Commit and push those files. On the staging server, pull the latest code and run:
drush config:import
After the import completes, verify parity:
drush config:diff
If the command returns no differences, staging now matches your local configuration. Only after that verification should you repeat the import on production.
Trade-offs and Sharp Edges
Configuration synchronization is powerful but blunt. The most common failure mode is accidental deletion. If you delete a view or content type locally and then export, the corresponding YAML file is removed from the sync directory. Importing that state elsewhere deletes the entity there too. Always review git diff output before committing an export.
Imports are effectively irreversible without a backup. An accidental config:import overwrites active configuration in the database. Your rollback path is Git: revert the commit and re-import, or restore a database snapshot taken before the operation. There is no built-in undo.
Module and core updates can introduce new configuration entities or change existing schemas. Importing configuration from a newer codebase into an older environment may fail or behave unexpectedly. Keep code and configuration deployments synchronized, and review diffs carefully when updating modules.
A Practical Checklist Before You Deploy
- Run
drush config:exportlocally and review every changed file withgit diff. - Commit only intentional changes; keep environment-specific overrides out of the shared sync directory.
- Deploy code first, then run
drush config:importon staging. - Run
drush config:diffon staging. If differences remain, stop and investigate. - Take a database backup before importing to production.
Treating configuration as code does not eliminate the need for caution, but it replaces guesswork with reviewable artifacts. The next time a view or content type behaves differently across environments, you will have the YAML to prove why.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.