DDEV for Drupal: a local workflow you can recreate

Laptop cu un site Drupal local și containere legate de repository, bază de date și fișiere încărcate.

When I take over a Drupal project or move it to a new computer, I do not try to rebuild the setup from memory. I reproduce the project environment: the PHP version, database, locked dependencies, and uploaded files. DDEV makes that more predictable by describing the environment in .ddev/config.yaml and running services in containers.

This guide covers three situations: starting a new project, bringing an existing site to my computer, and preparing a complete handoff for another environment. The key distinction is simple: code is only one part of a Drupal site. The database and public files travel separately, while secrets must be managed outside the package.

What I collect before importing

For an existing installation, I need the code revision that matches the database dump, composer.json and composer.lock, an SQL export, the public files directory, and any private files the project depends on. I also record the PHP and MariaDB or MySQL versions, along with services such as Redis or Solr.

I use anonymized data where possible and keep transfer archives outside the public document root. Before running an imported application, I check local settings and disable integrations that could send email or call production services.

Starting a new DDEV project

After installing DDEV and a supported Docker provider, I create the project directory, configure it, and start the containers. For a new Drupal 11 project, the DDEV Drupal quickstart is the right reference. The basic commands look like this:

mkdir -p ~/projects/drupal-local
cd ~/projects/drupal-local
ddev config --project-type=drupal11 --docroot=web
ddev start
ddev composer create-project drupal/recommended-project:^11 .
ddev composer require drush/drush

I then install the new site once and check its local address. That step is for a fresh database. I do not run site:install when I am trying to preserve an existing site's content.

Bringing an existing site to my computer

I clone the repository at the revision that matches the database and compare the DDEV configuration with the source environment. My current project, for example, is defined for PHP 8.4 and MariaDB 11.8. When I clone another project, I keep the versions that project requires instead of copying those values blindly.

git clone https://example.com/team/drupal-project.git ~/projects/drupal-project
cd ~/projects/drupal-project
ddev start
ddev composer install
composer install</code> reproduces the dependencies in the lockfile. <code>composer update</code> would resolve other versions and change the conditions of the import, so I reserve it for a planned dependency update.</p>
<p>Before importing the database, I check <code>settings.php</code> and local overrides. DDEV supplies the local database connection through <code>settings.ddev.php</code>; production credentials do not belong in local files or the repository. If the project uses additional services, I configure local equivalents or use the documented fallback.</p>
<p>The database and files are imported separately:</p>
<p><code>ddev import-db --file=/path/to/database.sql.gz
ddev import-files --source=/path/to/files.tar.gz
ddev drush cr
ddev drush status

The archive should contain the contents of the public files directory at its root, rather than nesting another files directory inside it. File import replaces the destination contents; it is not a way to merge collections. Private files and externally stored objects need a separate transfer.

Verify more than the homepage

After rebuilding caches, I check authentication, several articles, images, attachments, forms, search, and project-specific behavior. I review the status report and logs, then create or edit test content. A working homepage does not prove that files, cron, or integrations are all present.

A useful export contains more than SQL

For a restorable copy, I prepare the database, uploaded files, and code separately. Drupal configuration export describes structure and settings; it does not include content or users. The code revision must match the commit associated with the other exports.

mkdir -p ../handoff
ddev export-db --file=../handoff/database.sql.gz
tar -czf ../handoff/files.tar.gz -C web/sites/default/files .
ddev drush config:export -y
git archive --format=tar.gz --output=../handoff/code.tar.gz HEAD

Before sharing the package, I review the configuration changes and confirm that the Git archive contains the required files. git archive excludes uncommitted changes, ignored files, and submodules. I document the commit, PHP and database versions, and extra services. Secrets go through the team's approved secret manager, separately from the archives.

Restore the handoff on a second computer

The strongest handoff check is to restore it into a new directory. I extract the code, configure a distinct DDEV project name, install the locked dependencies, import the database and files, and rebuild caches. Then I repeat the functional checks. Missing extensions, private assets, and service settings are much easier to discover before another teammate receives the project.

An export is a snapshot of the site at one point in time; it is not a production deployment method. Importing a database over a live site can overwrite content and activity created since the export. For deployment, I follow the project's release workflow, move reviewed code and configuration, and preserve live content.

Commands I keep close

  • ddev start starts the project.
  • ddev describe shows URLs and services.
  • ddev drush status checks the installation.
  • ddev drush cr rebuilds Drupal caches.
  • ddev export-db and ddev import-db move the database.
  • ddev import-files brings in public files.

The official DDEV Drupal quickstart and DDEV database import guide are my references for command options that may change between releases.

Original article by Pavel Culacov. Written independently from hands-on Drupal and DDEV work; official documentation is linked for command details.