Migrating from Deployer to DeployHQ
Deployer is the PHP world's answer to what Capistrano was for Ruby: a deploy.php recipe, atomic symlinked releases, before/after hooks, and a dep deploy command that runs over SSH. For most PHP projects — Laravel, Symfony, plain old framework-less PHP — it has been the default for years.
This guide is for teams that have outgrown the file-and-CLI model and want a web UI, an audit log of every deploy, role-based deploy permissions, one-click rollback, and a build pipeline that runs off the target server rather than piped through SSH on every release. Deployer is not deprecated and your deploy.php will keep working — but a hand-rolled recipe is no longer the only sensible answer for production PHP deployments.
For a side-by-side feature comparison, see DeployHQ vs Deployer. If you are weighing alternatives across the PHP ecosystem, you may also want DeployHQ vs Envoyer. And if your deploy.php calls were already orchestrated from a CI pipeline rather than a human running dep deploy, Migrating from GitHub Actions to DeployHQ covers the hybrid pattern.
Coming from another script-based deploy tool? The migration shape for Capistrano is nearly identical — see Migrating from Capistrano to DeployHQ.
Feature parity: Deployer to DeployHQ
Everything dep deploy does, DeployHQ does. The configuration moves from a PHP file into a web UI; the deploy semantics stay the same.
| Deployer | DeployHQ |
|---|---|
deploy.php |
DeployHQ project (web-configured) |
host('prod.example.com')->set('deploy_path', '/var/www/app') |
Server entry with hostname, user, and deploy path |
set('repository', '...') |
Repository connection (Git, SVN, or Mercurial) |
set('branch', 'main') |
Branch per environment |
set('shared_files', [...]), set('shared_dirs', [...]) |
Shared paths configured once per environment |
Deployer release directory and current symlink |
Atomic deploy with automatic symlink swap |
task('deploy', [...]) and the deploy:* lifecycle |
Deploy lifecycle stages in the dashboard |
before() / after() hooks |
SSH commands tied to deploy lifecycle |
run('php artisan migrate'), run('composer install') |
SSH commands and build pipeline steps |
dep rollback |
One-click rollback to any prior deploy |
set('keep_releases', 5) |
Configurable release retention per environment |
host(...)->stage('production') (multi-stage) |
Native multi-environment per project |
Recipes (recipe/laravel.php, recipe/symfony.php) |
Pre-canned build pipeline + SSH command sets you wire once |
What DeployHQ adds that Deployer never did
| Capability | Why it matters |
|---|---|
| Web UI plus REST and GraphQL API | Deploy from a browser, a CLI, or a CI step. No dep binary, no PHP, and no deploy.php on the deploying machine. |
| Audit log of every deploy | Who deployed what, when, from which branch, with which commit hash. Deployer logs to your terminal scrollback. |
| Build pipelines | Run composer install --no-dev --optimize-autoloader, npm ci && npm run build, and asset builds once on our build infrastructure — not piped through run() on every target. Faster deploys, less server load. |
| AI deploy error explanation | When a deploy fails, the failed step is summarised in plain English with a likely fix. |
| DeployHQ CLI | deployhq deploy production from your terminal, scriptable in CI. |
| Per-environment permissions | Grant deploy-to-staging without granting deploy-to-production. Junior engineers can ship without root or repo write access. |
| Optional Managed VPS (beta) | Provision a server inside DeployHQ if you do not already have one. |
Migration in three steps
1. Connect your repository
Point DeployHQ at the same Git URL your set('repository', ...) line uses. Read-only deploy keys are generated automatically. DeployHQ checks out your code on our build infrastructure, so you do not need git on the target server.
2. Recreate your hosts as environments
Each host() definition in deploy.php becomes a server attached to a DeployHQ environment:
host('prod.example.com')->set('remote_user', 'deploy')becomes the server's hostname and SSH user.->set('deploy_path', '/var/www/app')becomes the environment deploy path.set('shared_files', ['.env'])andset('shared_dirs', ['storage', 'bootstrap/cache'])become shared files and shared paths.->set('branch', 'main')becomes the branch per environment.
If your deploy.php defines multiple stages (->stage('production'), ->stage('staging')), each stage maps to a separate DeployHQ environment. Multi-host stages — common in load-balanced setups — map to multiple servers attached to the same environment, deployed in parallel with the same atomic symlink swap.
3. Translate recipes and hooks into build pipeline + SSH commands
This is the bulk of the migration. Recipe steps (deploy:vendors, artisan:migrate, artisan:storage:link) and your custom before() / after() hooks become two kinds of DeployHQ artefact:
A typical Laravel deploy.php like this:
namespace Deployer;
require 'recipe/laravel.php';
set('repository', 'git@github.com:acme/shop.git');
host('prod.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/shop')
->set('branch', 'main');
after('deploy:vendors', 'artisan:migrate');
after('deploy:symlink', 'artisan:queue:restart');
after('deploy:symlink', 'artisan:horizon:terminate');
becomes, in DeployHQ:
composer install --no-dev --optimize-autoloader— moved into the build pipeline, so it runs once on our build server and thevendor/directory is uploaded with the release rather than installed on every target.npm ci && npm run build— also a build pipeline step, for the same reason.php artisan migrate --force— an SSH command set to run after upload, before changing the symlink.php artisan storage:link— an SSH command set to run on first deploy or as needed.php artisan queue:restartandphp artisan horizon:terminate— SSH commands set to run after deploy.php artisan config:cache && php artisan route:cache— SSH commands set to run after upload.
Symfony, plain PHP, and custom recipes follow the same shape: anything that produces or installs files becomes a build pipeline step; anything that runs on the target after upload becomes an SSH command bound to the right deploy stage.
For most Deployer projects, end-to-end migration is a half-day. Concierge migration is available on Pro and above — send us your deploy.php and we will rebuild the project with you on a screenshare.
What teams ask before they switch
Will my Deployer recipes (Laravel, Symfony, custom) survive? Yes. Recipes are just opinionated bundles of tasks and hooks. Each task that runs over SSH on the target moves to a DeployHQ SSH command; each task that produces artefacts (composer install, asset builds) moves to the build pipeline. Once wired, you never touch them again.
Can I keep using my existing servers? Yes. DeployHQ deploys to any SSH-reachable host. Bring your own VPS, dedicated server, or cloud instance.
What about my custom task() blocks? Anything that ran over SSH on the target server runs identically — it is just configured in the dashboard instead of deploy.php. Tasks that ran locally (e.g. building assets, packaging) move into the build pipeline.
Do you support multi-host deploys? Yes. Add multiple servers to one environment; DeployHQ deploys to all of them in parallel with the same atomic symlink swap.
What if I want to roll back? One click. DeployHQ keeps your last N releases on the server (you configure N). Rollback flips the symlink back. No dep rollback required.
Can I still trigger from CI? Yes — and this is often the cleanest setup. Keep your tests in GitHub Actions or GitLab CI and call dhq deploy as the deploy step. See Migrating from GitHub Actions to DeployHQ for the hybrid pattern.
My team is more familiar with Envoyer. Worth a look at DeployHQ vs Envoyer before committing — Envoyer is Laravel-specific and managed; DeployHQ supports any stack and integrates with build pipelines on our infrastructure. If you are migrating off Envoyer rather than Deployer, see Migrating from Envoyer to DeployHQ.
Start your migration
Start a free DeployHQ project — connect your repo, point at one server, and deploy in under 15 minutes. No credit card.
If you also need a server, the Managed VPS beta provisions one inside the same dashboard.
Deployer is a trademark of its respective maintainers. DeployHQ is not affiliated with the Deployer project. We just understand what graduating from a single-file deploy.php looks like.