This gist provides a minimal Laravel deployment setup using Composer as the single entry point, with Envoy treated as a setup-time dependency.
The deployment flow is intentionally simple: build the frontend locally, deploy only the final frontend assets, then update and optimize the Laravel backend on the production server.
This keeps the deployment model explicit, predictable, and infrastructure-light while remaining flexible enough for both local and automated deployments.
-
composer production:deploybuilds the frontend locally and runs the full deployment pipeline -
composer production:clear-cacheclears and rebuilds laravel caches on the production server
Important
- Envoy is an SSH automation tool, essentially a sugar-coated SSH client wrapper.
- Envoy is never executed on the target server. All commands run from the local machine (or runner) and are executed remotely over SSH.
- Ensure the machine running Envoy (local computer or CI runner) has SSH access explicitly allowed on the destination server.
- This setup works equally well for CI/CD pipelines, as long as the runner has SSH credentials and network access to the server.
- Please consult the official Laravel Envoy documentation first to avoid incorrect assumptions or unsafe usage.
Envoy is required only during setup and execution of deployment commands on your local machine.
composer require --dev laravel/envoyAdd the required deployment variables to your .env file:
ENVOY_SSH_HOST=your-server-host
ENVOY_SSH_PORT=22
ENVOY_PROJECT_ROOT_PATH=/var/www/your-projectInstead of running build and Envoy commands manually, Composer is used as the single interface for production operations:
Create an Envoy.blade.php file at the root of your project and define the deployment workflow:
@setup
include __DIR__.'/vendor/autoload.php';
Dotenv\Dotenv::createImmutable(__DIR__)
->safeLoad();
// Configuration
$serverHost = $_ENV['ENVOY_SSH_HOST'];
$serverPort = $_ENV['ENVOY_SSH_PORT'];
$projectPath = $_ENV['ENVOY_PROJECT_ROOT_PATH'];
if (in_array(null, [$serverHost, $serverPort, $projectPath])) {
throw new Exception(
'You must set ENVOY_SSH_HOST, ENVOY_SSH_PORT, and ENVOY_PROJECT_ROOT_PATH'
);
}
$localBuildPath = 'public/build/dist.zip';
$remoteTempPath = '~/tmp/dist.zip';
$remoteBuildPath = $projectPath . '/public/build';
@endsetup
@servers([
'production' => "$serverHost -p $serverPort",
'localhost' => '127.0.0.1',
])
@story('deploy')
upload_frontend_build
deploy_frontend_assets
update_backend_codebase
install_dependencies
optimize_application
restart_queues
@endstory
@task('upload_frontend_build', ['on' => 'localhost'])
scp -P {{ $serverPort }} {{ $localBuildPath }} {{ $serverHost }}:{{ $remoteTempPath }}
@endtask
@task('deploy_frontend_assets', ['on' => 'production'])
rm -rf {{ $remoteBuildPath }}
mkdir -p {{ $remoteBuildPath }}
unzip -o {{ $remoteTempPath }} -d {{ $remoteBuildPath }}
rm {{ $remoteTempPath }}
@endtask
@task('update_backend_codebase', ['on' => 'production'])
cd {{ $projectPath }}
git pull origin HEAD
@endtask
@task('install_dependencies', ['on' => 'production'])
cd {{ $projectPath }}
composer install --no-dev --optimize-autoloader
@endtask
@task('clear_cache', ['on' => 'production'])
cd {{ $projectPath }}
php artisan cache:clear
php artisan optimize:clear
php artisan optimize
@endtask
@task('optimize_application', ['on' => 'production'])
cd {{ $projectPath }}
php artisan optimize
@endtask
@task('restart_queues', ['on' => 'production'])
cd {{ $projectPath }}
php artisan queue:restart
@endtask
{ "scripts": { "production:clear-cache": "envoy run clear_cache", "production:deploy": [ "npm run build", "envoy run deploy" ] // .... } }