Drush config:import cheatsheet — managing Drupal config across environments
What is drush config:import?
Drupal stores site configuration — think field settings, view modes, content types, display modes, roles, permissions, module settings — as YAML files on disk. drush config:import (alias drush cim) reads those YAML files and applies them to the active database configuration.
This is the opposite of drush config:export (drush cex), which dumps the active database config out to YAML files.
The canonical workflow
Work locally, commit config to Git, let CI/CD deploy it to remote environments.
1
2
3
4
5
6
Local (DDEV) Git Remote (staging/prod)
──────────── ─── ─────────────────────
Make UI changes → commit config/sync → CI/CD runs on every deploy:
drush cex (or config/feature) git pull
drush config:import -y
drush cache:rebuild
config/sync/— the default. Use this for all regular config work. Full site config, versioned, deployed on every merge.config/feature/— use when you need to deploy a specific subset independently, e.g. a hotfix to one view without pulling in other unfinished config fromconfig/sync/.
Always run drush config:import on every deploy — even if no config changed. It’s idempotent: if the YAMLs haven’t changed, it’s a no-op. Safer than trying to conditionally skip it.
The benefits of config management
| Benefit | Why it matters |
|---|---|
| Version controlled config | See exactly what changed, when, and who changed it — same as code |
| Multi-environment deployments | Export on local, commit, import on staging/prod — no manual clicking through the UI |
| Code review for config | Config changes go through PRs just like code changes |
| Disaster recovery | Recreate any environment from scratch using code + config |
| Feature flags / partial deploys | Ship just the config for one feature without touching everything else |
Start simple — the default config sync
The most common usage is a full sync using the default config/sync/ directory. This is where Drupal stores all your site config by default.
Export (local → files)
1
2
3
4
5
# Inside DDEV
ddev drush config:export
# Outside DDEV
drush config:export
This writes all active database config to config/sync/ as YAML files. Commit these to Git.
Import (files → database)
1
2
3
4
5
# Inside DDEV
ddev drush config:import
# Outside DDEV
drush config:import
This reads the YAML files in config/sync/ and syncs them into the active database. A full import will delete any config in the DB that isn’t present in the sync directory — it’s a true sync, not a merge.
Always rebuild cache after importing:
1
drush cache:rebuild
Feature config — partial imports
Once you’re comfortable with the default workflow, partial imports let you deploy just a subset of config — useful when you have a feature directory or only want to push specific changes without a full sync.
1
drush config:import --partial --source=/var/www/html/config/feature
| Flag | What it does |
|---|---|
--partial | Only import the YAMLs present in the source directory — don’t delete configs that exist in the DB but are absent from the source |
--source=PATH | Read YAMLs from this directory instead of the default sync directory |
Why --partial matters
Without --partial, a full sync would delete any config in the DB not present in the source directory. When you’re only importing a feature subdirectory, that would wipe out all your other config. --partial makes it additive/update-only.
How to build a feature config directory
1
2
3
4
5
6
# Option 1 — export directly to a feature directory
drush config:export --destination=/var/www/html/config/feature
# Option 2 — manually copy specific YAMLs from your full sync
cp config/sync/views.view.my_view.yml config/feature/
cp config/sync/field.field.node.article.body.yml config/feature/
Then commit and import the same way:
1
2
3
4
5
6
git add config/feature/
git commit -m "Export view config for my-feature"
# On target environment
drush config:import --partial --source=/var/www/html/config/feature
drush cache:rebuild
Ideal workflows
Solo developer
You’re the only one touching config so conflicts are rare. The main discipline is: always export before you commit code that depends on config changes. The trap is writing a module or template that relies on a field or view you set up in the UI, then forgetting to export — it breaks on the next environment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. Make config changes in the Drupal UI
# 2. Export
ddev drush config:export
# 3. Review the diff — only commit YAMLs you intentionally changed
git diff config/sync/
# 4. Commit and push
git add config/sync/
git commit -m "Export config: updated news view"
git push
# 5. On staging/prod
git pull
drush config:import
drush cache:rebuild
Team workflow
This is where it gets more nuanced — two developers can both change config locally, creating conflicts in YAML files. Treat config exactly like code: export it, review it, merge it.
Golden rule: always sync before you start work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. Before starting work — get your local DB in sync with the team
git pull
ddev drush config:import
# 2. Do your UI changes locally
# 3. Export and review the diff
ddev drush config:export
git diff config/sync/ # only commit what you intentionally changed
# 4. Commit in its own commit, then raise a PR
git add config/sync/
git commit -m "Config: add body field to article content type"
# 5. Teammate reviews the YAML diff in the PR (same as reviewing code)
# 6. On merge, staging/prod deploy runs:
drush config:import -y
drush cache:rebuild
Handling YAML merge conflicts — When two devs both export different config states, Git will flag conflicts in the YAML files. They’re usually readable and can be resolved manually the same way you’d resolve a code conflict. Keep config exports small and focused to minimise conflicts.
Recommended team conventions
| Convention | Why |
|---|---|
| Pull + import before starting any config work | Avoids diverging from the team’s current state |
| Config changes in their own commit | Keeps diffs clean and reviewable |
| One person owns config export per feature | Avoid two devs exporting different states simultaneously |
--partial for feature-level work only | Use full cim for main branch deploys |
| Never import on production without a DB backup | drush sql:dump first, always |
CI/CD runs drush config:import on every deploy | Automates it, removes human error |
CI/CD deploy script
1
2
3
4
5
git pull
composer install --no-dev
drush updatedb -y # run DB updates from module upgrades
drush config:import -y # apply config changes
drush cache:rebuild
Multi-environment flow at a glance
1
2
Local dev → Git commit config → Staging → Production
cex push cim cim
When do you need to run it?
Run drush config:import when:
- Deploying code that includes config changes (views, fields, content types, permissions, etc.)
- A teammate has updated config on their local and pushed it to Git
- After enabling or updating a module that ships with config
- After a
git pullthat includes YAML file changes — if you don’t run it, the DB and files are out of sync
Always run drush cache:rebuild (drush cr) after importing config.
Safe usage checklist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. Check what will change BEFORE applying it
drush config:import --preview
# or
drush config:import --diff
# 2. Backup the database first (especially on staging/prod)
drush sql:dump --result-file=/tmp/backup-before-cim.sql
# 3. Run the import
drush config:import
# 4. Rebuild cache
drush cache:rebuild
# 5. Verify in the UI
Common flags
| Flag | Purpose |
|---|---|
--partial | Only import files in source dir, don’t delete unmatched configs |
--source=PATH | Import from a custom directory instead of the default sync dir |
--preview | Show a diff of what will change without applying it |
--diff | Same as preview but outputs as a unified diff |
-y | Auto-confirm without prompting (useful in CI/CD pipelines) |
Common gotchas
Config UUID mismatch — If you import config from a completely different site install, Drupal will refuse. Each Drupal install has a unique UUID stored in system.site.yml. You can override it:
1
drush config:set system.site uuid "the-uuid-from-your-source-site"
Config out of sync after module enable — After enabling a module, always import config if the module ships config YAML files in its config/install/ directory.
Partial import missing dependencies — If a YAML file references a config entity that doesn’t exist yet (e.g. a field that hasn’t been created), the import will fail. Import dependencies first or do a full config import.
Quick reference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Export full config
drush config:export # drush cex
# Import full config
drush config:import # drush cim
# Preview changes without applying
drush config:import --preview
# Backup DB then import
drush sql:dump --result-file=/tmp/pre-cim.sql && drush config:import
# Import partial (feature/subset only)
drush config:import --partial --source=config/feature
# Inside DDEV
ddev drush config:import --partial --source=/var/www/html/config/feature