Skip to content

Introduction

ddev-sync pulls a project’s production database, files and setup commands into a local DDEV environment — and leaves the production data behind while doing it.

It replaces the sequence most teams otherwise repeat by hand: dump the remote database over SSH, import it locally, rsync the uploads, point the local app at the local database, anonymise what came across, and run the framework’s own post-import commands. What those commands are is decided by a profile per project type, so the tool knows that TYPO3 wants vendor/bin/typo3 cache:flush where Laravel wants php artisan optimize:clear.

ddev-sync installs in one command from its published release, and the release is a candidate. ddev add-on get NoiXdev/ddev-sync installs the newest one and the container image is pulled for you; Installation has the commands. A bare add-on get reaches a candidate because DDEV takes the newest release without setting pre-releases aside — which is what makes this installable at all today, and also means the version moves when the next candidate is published.

What is tested, and how. Every change runs the engine’s own suite with full coverage, an integration suite that drives real containers over real SSH, and a verification matrix of eleven cells that each install a real framework and sync it through a container-based engine: TYPO3 12 and 13, Laravel, Symfony, Drupal and WordPress, three of them again with features switched on, and one that syncs a real Laravel through a Docker endpoint. Shopware has a profile but no cell, so nothing about its commands has been run. The add-on packaging has its own suite in CI: it installs the newest release into a real DDEV project, starts it with no image override anywhere, runs ddev sync --version and removes it again. Which sanitize rules have been exercised against a real installation is a narrower question, recorded per variant and summarised in the profiles reference.

What has not happened yet. No sync against a real production host has been run through the add-on — the matrix and the integration suite sync against stand-ins that this project builds, which is a different thing from your server. The add-on itself has been exercised by hand on macOS with Docker Desktop and DDEV 1.25.4, and in CI on Ubuntu runners; Colima, OrbStack, rootless Docker and Windows have not been tried.

StepWhat happens
dbmysqldump over SSH, streamed straight into the local database — no dump file left on the remote
filesrsync of the paths the profile declares: uploads, fileadmin, storage/app/public
s3rclone between two S3 endpoints, for projects whose media lives in a bucket
sanitizeTruncates sessions and queues, anonymises user tables, resets passwords, creates a local admin
setupThe framework’s own commands: composer install, migrations, cache rebuilds

Steps are selected with --steps; db, files and sanitize are the default when you are asked interactively. setup is deliberately not a default, because it runs composer install and frontend builds that can take minutes.

Nothing is ever pushed. The remote is only ever read — there is no direction of this tool that writes to production, by design and not by configuration.

A production database on a laptop is the problem ddev-sync exists to solve, not a side effect it tolerates. The sanitize step is what makes a copy safe to work with: it empties session and queue tables, rewrites user email addresses to unreachable ones, replaces password hashes with a value nothing can authenticate against, and creates a local administrator you can actually log in with.

Those rules are declared per project type, and a rule that has never been run against a real installation can silently do nothing — a table that does not exist under that name, or a command that was never a command. Which rules have actually been exercised against a real installation, and which have not, is recorded per variant in the project’s profiles/VERIFIED.md. The profiles reference summarises it.

Profiles ship for TYPO3 (9 through 13), Laravel, Symfony, WordPress, Drupal and Shopware 6, plus a generic fallback for DDEV project types with no dedicated profile. Optional features add work on top when they detect something — a frontend build when package.json has a build script, Horizon’s queue handling on a Laravel project that uses it.

The sync runs against DDEV’s own containers and reaches the remote over your existing SSH agent — the same keys ddev auth ssh loads into DDEV’s agent. There is no account to create, no credentials stored by the tool itself, and no telemetry.