db-import / db-export: two global DDEV commands to manage your dumps

After juggling between several DDEV projects for a while, I got tired of rewriting the same little database import and export scripts in every repository. Good news: DDEV can load global custom commands. Dropped into ~/.ddev/commands/host/, they are available in every DDEV project on the machine, with nothing to install on the project side. Here are the two I use every day: ddev db-import and ddev db-export.

The working assumption is that, for each project, my dumps live in a ./files/dumps folder at the root of the project.

ddev db-import: restoring a database

The command empties the database, imports a dump, then runs drush deploy, drush cr and drush uli: everything you need to start over from a freshly fetched production dump, in a single command. Without an argument, it picks the most recent dump (by modification date) from the dumps folder:

ddev db-import                         # most recent dump
ddev db-import dump.sql.gz             # file name only: looked up in the dumps folder
ddev db-import chemin/vers/dump.sql.gz # specific dump
ddev db-import -l                      # list dumps, newest first

The argument is first resolved as is (absolute path or relative to the project root), then in the dumps folder, so a plain file name is enough. Supported formats are those of ddev import-db: .sql, .sql.gz, .sql.bz2, .sql.xz, .mysql, .mysql.gz, .zip, .tgz, .tar.gz.

Important point: the database really is emptied before the import. ddev import-db takes care of it (it drops the database by default, see its --no-drop flag). That is more robust than a drush sql:drop, which requires a Drupal able to bootstrap… which is far from guaranteed when the database is precisely the thing that is broken.

Latest convenience: the dump name autocompletes. ddev db-import <tab> suggests the dumps from the dumps folder, newest first (the mechanism is detailed below).

ddev db-export: dumping the database

The counterpart of the import: the command clears the caches (drush cr, so as not to ship full cache tables) then exports to <dossier>/<horodatage>-<projet>-dev.sql.gz. Compressed by default:

ddev db-export             # -> 2026-07-27_14-30-00-monprojet-dev.sql.gz
ddev db-export --no-gzip   # -> uncompressed .sql
ddev db-export -n          # dry-run
ddev db-export --no-cr     # without clearing the cache first

Thanks to the timestamped file name, the "most recent dump" picked by db-import is always the right one: the two commands naturally work together.

The dumps folder: DB_DUMP_DIR

Both commands share the same dumps folder: files/dumps by default (relative to the project root), which can be overridden per project with the DB_DUMP_DIR variable, in the .env file at the root or in .ddev/.env, as a relative or absolute path:

# project .env: the base value (the one used without any configuration)
DB_DUMP_DIR=files/dumps

# can be overridden with another folder, relative to the project root…
DB_DUMP_DIR=dumps
# … or absolute
DB_DUMP_DIR=/chemin/absolu/vers/dumps

The priority order is: environment variable > .env > .ddev/.env > default. db-export creates the folder if it is missing; db-import fails cleanly if it does not exist. A detail that matters: the .env file is never sourced. The variable is extracted with grep, because sourcing a .env file means executing its content.

Autocompletion

This mechanism is poorly documented and worth a look: a script with the same name as the command, placed in ~/.ddev/commands/host/autocomplete/, is called by DDEV on every <tab> and writes its suggestions to standard output, one per line; prefix filtering is handled by DDEV and the shell. The autocomplete/ subfolder is not registered as a command (just like shells/), so it does not clutter ddev -h.

The one for db-import lists the dumps from the dumps folder, newest first. Two precautions in this particular context: since DDEV_APPROOT is not guaranteed under <tab>, the script falls back to walking up the directory tree until it finds .ddev/config.yaml; and it exits silently (no suggestions) at the slightest problem: never an error message in the middle of a command line. Tested on DDEV 1.25.

The code

Since this post was published, these commands have been packaged, together with a few others of the same kind, into a global DDEV add-on, ddev-drupal-tools, which installs in one line:

ddev add-on get kgaut/ddev-drupal-tools

(run it from a DDEV project folder, or with --project <nom>; installing, updating and removing it are detailed in the repository README)

Rather than copying the sources here, you might as well read them directly in the repository: db-import, db-export and the db-import autocompletion. For a manual installation, drop the files into ~/.ddev/commands/host/ and make them executable (chmod +x): no need to restart anything, DDEV discovers them on its own.

Written by Kevin Gautreau — freelance PHP/Drupal developer & trainer in Auvergne, France. get in touch

Comments (0)