host(string ...$hostname): Host|ObjectProxyDefine one or more hosts for deployment.
host('example.org');
host('prod.example.org', 'staging.example.org');Inside a task, returns the Host instance for the given alias:
task('test', function () {
$port = host('example.org')->get('port');
});localhost(string ...$hostnames): Localhost|ObjectProxyDefine a local host. Commands run on the local machine instead of over SSH.
localhost('ci'); // Alias and hostname will be "ci".currentHost(): HostReturn the host the current task is running on.
task('whoami', function () {
writeln(currentHost()->getAlias());
});select(string $selector): arrayReturn hosts matching a selector expression.
on(select('stage=prod, role=db'), function (Host $host) {
// Runs on hosts tagged stage=prod AND role=db.
});selectedHosts(): arrayReturn the hosts the user picked on the command line.
import(string $file): voidImport another recipe (PHP or MAML).
Built-in recipe/* and contrib/* paths are already on PHP's include path,
so they can be imported by relative path. Use __DIR__ for files inside
your own project.
import('recipe/common.php'); // built-in recipe
import('contrib/rsync.php'); // contrib recipe
import(__DIR__ . '/config/hosts.maml'); // local filedesc(?string $title = null): ?stringSet the description for the next task defined with task().
desc('Restart php-fpm');
task('restart', function () {
run('sudo systemctl restart php-fpm');
});Calling desc() with no argument returns the pending description.
task(string $name, callable|array|null $body = null): TaskDefine a task, or return an already defined one.
Pass a callback to define a single task:
task('deploy:run', function () {
run('echo deploying');
});Pass an array of task names to define a group task:
task('deploy', ['deploy:update_code', 'deploy:vendors', 'deploy:symlink']);Pass only the name to fetch an existing task:
task('deploy')->desc('Run full deploy');| Argument | Type | Comment |
|---|---|---|
$name |
string |
Task name. |
$body |
callable or array or null |
Callback, list of task names, or null to fetch an existing task. |
before(string $task, string|callable $do): ?TaskRun a task (or callback) before another task.
before('deploy:symlink', 'deploy:cache:warmup');
before('deploy:symlink', function () {
run('echo about to symlink');
});| Argument | Type | Comment |
|---|---|---|
$task |
string |
Name of the task to attach the hook to. |
$do |
string or callable |
Task name or callback to run. |
after(string $task, string|callable $do): ?TaskRun a task (or callback) after another task.
after('deploy:symlink', 'deploy:cleanup');
after('deploy:failed', function () {
run('echo something went wrong');
});| Argument | Type | Comment |
|---|---|---|
$task |
string |
Name of the task to attach the hook to. |
$do |
string or callable |
Task name or callback to run. |
fail(string $task, string|callable $do): ?TaskRun a task (or callback) when another task fails.
Calling fail() again for the same task replaces the previous handler.
fail('deploy', 'deploy:unlock');
fail('deploy', function () {
run('echo rollback triggered');
});| Argument | Type | Comment |
|---|---|---|
$task |
string |
Name of the task whose failure triggers $do. |
$do |
string or callable |
Task name or callback to run on failure. |
option(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null): voidAdd a CLI option to the dep binary.
use Symfony\Component\Console\Input\InputOption;
option('tag', null, InputOption::VALUE_REQUIRED, 'Release tag');
task('deploy', function () {
$tag = input()->getOption('tag');
});| Argument | Type | Comment |
|---|---|---|
$name |
string |
Option name (long form, no leading dashes). |
$shortcut |
string or array or null |
Single-letter shortcut, ` |
$mode |
int or null |
One of the InputOption::VALUE_* constants. |
$description |
string |
Help text shown in dep --help. |
$default |
string or string[] or int or bool or null |
Default value (must be null for VALUE_NONE). |
cd(string $path): voidChange the current working directory.
Both cd() and the cwd: argument of run() change the working directory
for executed commands. The difference: cd() changes it for the rest of the
current task, while cwd: overrides it for a single run() call only.
set('deploy_path', '~/deployer.org');
task('task1', function () {
cd('{{deploy_path}}');
run('pwd');
// output: /home/deployer/deployer.org
run('pwd', cwd: '/usr'); // Override working dir for this run only.
// output: /usr
run('pwd');
// output: /home/deployer/deployer.org
});Note that cd() only changes the working directory within a single task.
The next task starts fresh.
task('task2', function () {
run('pwd'); // cd from previous task is not used.
// output: /home/deployer
});
task('all', [
'task1',
'task2',
]);become(string $user): \ClosureSwitch the user that run() uses for subsequent commands.
Returns a closure that restores the previous user when called.
$restore = become('deployer');
run('whoami'); // deployer
$restore();within(string $path, callable $callback): mixedRun a callback inside a working directory, then restore the previous one.
Use this when you need a scoped cd() that does not leak to the rest of the task.
within('{{release_path}}', function () {
run('composer install');
});run(
string $command,
?string $cwd = null,
?array $env = null,
#[\SensitiveParameter]
?array $secrets = null,
?bool $nothrow = false,
?bool $forceOutput = false,
?int $timeout = null,
?int $idleTimeout = null,
): string Run a command on the current remote host and return its trimmed stdout.
run('echo hello world');
run('cd {{deploy_path}} && git status');
run('curl medv.io', timeout: 5);
$path = run('readlink {{deploy_path}}/current');
run("echo $path");Pass secrets via placeholders (e.g. %token%) so they are redacted in logs:
run('curl -u admin:%token% https://api.example', secrets: ['token' => getenv('TOKEN')]);Use the | quote filter to escape config values as shell arguments:
run('echo {{ message | quote }}');
run('grep -r {{ pattern | quote }} {{release_path}}');To emit a literal {{, escape it with a backslash:
run('echo \{{not_replaced}}'); // outputs: {{not_replaced}}| Argument | Type | Comment |
|---|---|---|
$command |
string |
Command to run on the remote host. |
$cwd |
string or null |
Working directory for this run. Defaults to {{working_path}} (set by cd()). |
$timeout |
int or null |
Max runtime in seconds (default: {{default_timeout}}, 300; null disables). |
$idleTimeout |
int or null |
Max seconds without output before aborting. |
$secrets |
array<string, scalar> or null |
Map of %name% placeholders to redacted values. |
$env |
array<string, scalar> or null |
Environment variables: run('echo $KEY', env: ['KEY' => 'value']); |
$forceOutput |
bool or null |
Print command output in real time. |
$nothrow |
bool or null |
Return output instead of throwing on non-zero exit. |
runLocally(
string $command,
?string $cwd = null,
?int $timeout = null,
?int $idleTimeout = null,
#[\SensitiveParameter]
?array $secrets = null,
?array $env = null,
?bool $forceOutput = false,
?bool $nothrow = false,
?string $shell = null,
): string Run a command on the local machine and return its trimmed stdout.
$branch = runLocally('git rev-parse --abbrev-ref HEAD');
runLocally('npm run build', timeout: 600);| Argument | Type | Comment |
|---|---|---|
$command |
string |
Command to run locally. |
$cwd |
string or null |
Working directory for this run. Defaults to {{working_path}}. |
$timeout |
int or null |
Max runtime in seconds (default 300, null disables). |
$idleTimeout |
int or null |
Max seconds without output before aborting. |
$secrets |
array<string, scalar> or null |
Map of %name% placeholders to redacted values. |
$env |
array<string, scalar> or null |
Environment variables: runLocally('echo $KEY', env: ['KEY' => 'value']); |
$forceOutput |
bool or null |
Print command output in real time. |
$nothrow |
bool or null |
Return output instead of throwing on non-zero exit. |
$shell |
string or null |
Shell to run in. Default bash -s. |
test(string $command): boolReturn whether a shell test command succeeds on the remote host.
if (test('[ -d {{release_path}} ]')) {
run('rm -rf {{release_path}}');
}testLocally(string $command): boolReturn whether a shell test command succeeds on the local machine.
if (testLocally('[ -f .env ]')) {
upload('.env', '{{release_path}}/.env');
}on($hosts, callable $callback): voidRun a callback on each given host.
on(select('stage=prod, role=db'), function (Host $host) {
run('mysqldump app > /tmp/backup.sql');
});
on(host('example.org'), function (Host $host) {
run('uptime');
});
on(Deployer::get()->hosts, function (Host $host) {
run('uname -a');
});invoke(string $taskName): voidRun another task by name from inside the current task.
task('deploy', function () {
invoke('deploy:update_code');
invoke('deploy:symlink');
});upload($source, string $destination, array $config = []): voidUpload files or directories to the current host via rsync.
To copy the contents of a directory, end the source with /:
upload('build/', '{{release_path}}/public'); // copies contents of build/
upload('build', '{{release_path}}/public'); // copies the build/ dir itself$config keys:
flags: replaces the default-azPflagsoptions: extra flags appended to the rsync commandtimeout: process timeout in seconds (null= no limit)progress_bar: show transfer progressdisplay_stats: show rsync statistics
Note: PHP shell-escaping breaks rsync's --exclude={'a','b'} brace list.
Pass each exclude as its own --exclude=... option, or use --exclude-from=<file>.
download(string $source, string $destination, array $config = []): voidDownload a file or directory from the current host via rsync.
download('{{deploy_path}}/.dep/database.sql', 'backup/database.sql');$config accepts the same keys as upload().
info(string $message): voidPrint an info message, prefixed with info and the host alias.
info('Deployed release {{release_name}}');warning(string $message): voidPrint a warning message.
writeln(string $message, int $options = 0): voidWrite a line to the output, prefixed with the current host alias.
The message is parsed for {{config}} placeholders before printing.
parse(string $value): stringReplace {{name}} placeholders in a string with values from the current config.
$current = parse('{{deploy_path}}/current');set(string $name, $value): voidSet a global config value.
set('keep_releases', 5);
set('shared_files', ['.env']);add(string $name, array $array): voidAppend values to an array config option.
add('shared_files', ['.env']);
add('shared_dirs', ['storage/logs']);get(string $name, $default = null)Return a config value, or $default if it isn't set.
Callable values are resolved on first access and cached.
$branch = get('branch', 'main');has(string $name): boolReturn whether a config option is set.
ask(string $message, ?string $default = null, ?array $autocomplete = null): ?stringPrompt the user for a string, on the current host.
Returns $default in quiet mode (-q).
$branch = ask('Branch to deploy?', 'main');
$tag = ask('Tag?', null, ['v1.0', 'v1.1', 'v1.2']);askChoice(string $message, array $availableChoices, $default = null, bool $multiselect = false)Prompt the user to pick one or more values from a list.
$color = askChoice('Pick a color', ['red', 'green', 'blue'], 0);| Argument | Type | Comment |
|---|---|---|
$default |
mixed |
Key into $availableChoices, or null for no default. |
askConfirmation(string $message, bool $default = false): boolPrompt the user with a yes/no question. Returns $default in quiet mode.
if (askConfirmation('Drop the database?')) {
run('mysql -e "DROP DATABASE app"');
}askHiddenResponse()
askHiddenResponse(string $message): stringPrompt the user for input without echoing it. Use for passwords and tokens.
input(): InputInterfaceReturn the Symfony Console input, e.g. to read CLI options.
$tag = input()->getOption('tag');output(): OutputInterfaceReturn the Symfony Console output, e.g. to check verbosity.
commandExist(string $command): boolReturn whether a command is available on the current host's PATH.
if (!commandExist('git')) {
throw error('git is required to deploy');
}commandSupportsOption(string $command, string $option): boolReturn whether a command's man page or --help output mentions the given option.
Useful for picking newer flags only when the installed version supports them.
$progress = commandSupportsOption('rsync', '--info=progress2') ? '--info=progress2' : '--progress';which(string $name): stringReturn the absolute path of a command on the current host.
Tries command -v, then which, then type -p.
$php = which('php');
run("$php -v");remoteEnv(): arrayReturn the remote host's environment as an associative array.
$remotePath = remoteEnv()['PATH'];
run('echo $PATH', env: ['PATH' => "/home/user/bin:$remotePath"]);error(string $message): ExceptionBuild a Deployer Exception with {{config}} placeholders parsed in the message.
if (!commandExist('git')) {
throw error('git is required on {{alias}}');
}timestamp(): stringReturn the current UTC timestamp in ISO 8601 format.
quote(string|int $arg): stringQuote a string for safe use as a shell argument (ANSI-C $'...' syntax).
Strings made of safe characters (alphanumeric, /.-+@:=,%) are returned unquoted.
Throws on null bytes.
run('git log --format=' . quote($format));
run('echo ' . quote("it's a test")); // echo $'it\'s a test'fetch(string $url, string $method = 'get', array $headers = [], ?string $body = null, ?array &$info = null, bool $nothrow = false): stringMake an HTTP request and return the response body.
Pass $info by reference to capture status code, headers, and timing
(same shape as PHP's curl_getinfo). Use nothrow: true to receive the
body even on non-2xx responses.
$body = fetch('{{domain}}/health', info: $info);
if ($info['http_code'] !== 200) {
throw error("health check failed: {$info['http_code']}");
}
fetch('https://api.example.com/notify', 'post',
['Authorization' => 'Bearer {{token}}'],
json_encode(['release' => '{{release_name}}']),
);