Migrating from Craft Nitro to DDEV

With Nitro being discontinued, we recommend DDEV as a great local development environment:

  • It’s Docker-based, freely available, and it works on macOS, Windows, and Linux.
  • It’s well documented and has an active community.
  • It’s perfect for PHP-based projects like Craft.
  • It’s a convenient layer on top of Docker, and you can bring as little or as much Docker as you want.

For each site you migrate, you’ll need to grab a database export (from Nitro or your production environment), create and configure a new DDEV site, and import the database.

Most sites should only take a few minutes to migrate.

1. Export existing databases #

Pick either method for exporting each site’s database:

  • From your production environment, you can visit the Craft control panel (with sufficient permissions) and navigate to UtilitiesDatabase Backup, make sure Download backup is checked, and press Backup. This will create and download a compressed database dump.
  • From your local machine with Nitro installed, you can run nitro db backup and choose each engine and database. (Take note of the directories these are saved to, or collect the backups someplace more convenient for step 5.)

While you can use tools like pg_dump and mysqldump, we recommend using Craft or Nitro’s export options because they’re configured to keep things consistent and encourage a smooth experience.

2. Stop Nitro #

Running Nitro and DDEV simultaneously may invite port conflicts, so we’ll stop Nitro to ensure that DDEV will be the only local environment running.

You can stop all Nitro’s containers using the stop command:

nitro stop

3. Install DDEV #

Follow DDEV’s documentation get it installed and running on your OS.

4. Create DDEV sites #

In the same way you’ve used nitro add to create a site with Nitro, you’ll use ddev config to create a site with DDEV.

  1. Navigate to your project directory, run ddev config, and follow the prompts. The auto-detected docroot (web) and project type (craftcms) should work for most projects, but you can pass them explicitly if you're using a non-standard setup: ddev config --project-type=craftcms --webroot=app/public.
  2. Open the newly-created .ddev/config.yaml to adjust settings.
    • Set php_version to whichever you need. (More in config.yaml’s comments.)
    • The database type can be mariadb, mysql, or postgres with a corresponding version.
    • Use additional_hostnames for other *.ddev.site domain names you’d like to use, or additional_fqdns for other custom domain names.
  3. Run ddev start to prepare and run the containers needed for the site.
  4. Run ddev describe to get details about the site, and update Craft’s settings with new path and database connection details:
    • CRAFT_DB_SERVER=my-site-db (DDEV InDocker hostname)
    • CRAFT_DB_USER=db
    • DEFAULT_SITE_URL=my-site.ddev.site (DDEV web URL)

This will write a .ddev/ directory at the root of the project. You can either add that directory to your .gitignore file or check it into your project to share with other developers and/or machines.

DDEV’s default container path is /var/www/html, so you may need to update any references to Nitro’s /app directory. If your web root is /app/web, for example, it will become /var/www/html/web.

Any time you’ve saved edits to .ddev/config.yaml, you can use ddev start to apply them and restart the container(s).

5. Import databases #

From each project directory, import the database export you prepared in step 1:

ddev import-db --src=dump.sql

That’s it! You should be able to run ddev launch to open your freshly-migrated site in a browser.

6. Uninstall Nitro #

To remove Nitro from your system, run nitro destroy and follow the OS-specific instructions for removing the system components that are left.

Getting Oriented #

At a high level, Nitro and DDEV are not wildly different. DDEV offers a lot of additional functionality and some key architectural differences:

  • Each project has its own YAML and supporting configuration files, and generates intermediate Docker Compose YAML you can customize (or never look at!) depending on your needs.
  • Each project is more tightly coupled to its database, which runs in its own separate database container.
  • Projects can be independently started and stopped.
  • You can add first- and third-party services like you could with Nitro, but you can customize further with config file conventions, hooks, Docker Compose, and whatever custom images you’d like to introduce.

Connecting to the Database #

DDEV is similar to Nitro in that you’ll need to be mindful about connecting to the database container externally or within another Docker container.

Use ddev describe to see project details that include a db section. The InDocker details are what you’d provide Craft, while the Host details are what you’d use externally for something like a GUI client. (Notice the Host port, which will change with each project.)

Credentials will always be db for the username, password, and database.

macOS users with TablePlus installed can use ddev tableplus to open the current project’s database without entering any connection details. DDEV has commands for other database GUIs, as well!

Starting and Stopping Projects #

Each project can be started with ddev start, which will apply any configuration changes. ddev pause will pause a project’s containers, and ddev stop will remove the containers while preserving data. (You can use ddev stop --remove-data to remove all project data.)

To have DDEV remove and forget everything about a project including its configuration, use ddev delete --omit-snapshot --yes.

Xdebug #

Nitro’s xon and xoff commands become ddev xdebug on and ddev xdebug off, and you’ll need to remap PhpStorm and VS Code to the container’s new folder structure. (/app/var/www/html.)

Learn more in the DDEV docs. There’s also a video tutorial on configuring PhpStorm and DDEV.

Redis #

Redis isn’t included with a new site, but the first-party service is quick to add:

ddev get drud/ddev-redis
ddev restart

You’ll need to provide Craft with your the new Redis container’s hostname, which you can find running ddev describe.

If you’ve configured your Craft site like the examples in the documentation, you can specify the hostname in your .env file:


Custom Ports #

DDEV automatically notifies you about any port conflicts so that you can stop conflicting services. You can also configure DDEV to use non-conflicting ports from .ddev/config.yaml.

Learn more in the DDEV docs.

MailHog #

MailHog is included by default with each new DDEV site.

Run ddev describe to get that project’s MailHog URL, or run ddev launch -m.

Node.js & npm #

Each web container comes preinstalled with node, npm, nvm, and yarn. You can configure the default versions and override that with the ddev nvm command.

If you run any additional web servers inside the web container—Vite or webpack, for example—you’ll need to use a custom Docker Compose file to open the ports you’d like to use. One Darnley Road’s starter project has a great example for using Vite with port 3000.

Cheat Sheet #

Most Nitro commands have a DDEV equivalent.

Nitro CommandDDEV Command
nitro addddev config
nitro applyddev start
nitro bridgeNo DDEV equivalent.
nitro cleanddev clean
nitro completionSee Adding Shell Completion (bash, zsh, etc.).
nitro composerddev composer
nitro contextddev describe
nitro craftddev php craft
nitro db addddev import-db --target --src (see docs)
nitro db backupddev export-db
nitro db destroyNo 1:1, but ddev delete removes project information including the database.
nitro db importddev import-db
nitro db newEach engine is created when adding a database.
nitro destroySee Uninstalling DDEV.
nitro disableddev service disable
nitro editNo DDEV equivalent.
nitro enableddev service enable
nitro extensionsNo 1:1. See Providing custom PHP configuration (php.ini).
nitro helpddev help
nitro hostsddev hostname
nitro inisetStatic files. See Extending and Customizing Environments.
nitro initResources initialized on demand.
nitro logsddev logs -f
nitro lsddev list
nitro npmddev exec npm
nitro phpddev php
nitro portcheckPort conflicts are automatically called out.
nitro queueddev php craft queue/listen --verbose
nitro removeddev delete
nitro restartddev restart
nitro self-updateDepends on install method. See Installation.
nitro shareddev share
nitro sshddev ssh
nitro startddev start
nitro stopddev poweroff
nitro trustn/a
nitro updateddev config + ddev start for each project.
nitro validateProject YAML validated on the fly. (i.e. for ddev start)
nitro versionddev version
nitro xoffddev xdebug off
nitro xonddev xdebug / ddev xdebug on

Shell Aliases #

If a common command like ddev php craft or ddev xdebug on is a bit too much keyboarding, you can create your own shell aliases:

alias ddev-craft="ddev exec php craft"
alias ddev-xon="ddev xdebug on"
alias ddev-xon="ddev xdebug off"

Troubleshooting #

If you run into issues with your migrated sites, check out Troubleshooting a Failed Craft Installation and Troubleshooting Database Connection Issues.

If you’ve got an internal server error that’s not generating application-level logs, you may be able to use ddev logs -f to take a look at relevant container logs as they’re written.

If all else fails, consider troubleshooting in the #devops channel in the Craft CMS Discord server or popping by DDEV’s own Discord server.

Further Reading #

Community Starter Projects #

Applies to Craft CMS 4.