thebytelab/vapor-multi-region-deploy
Deploy Laravel Vapor applications across multiple AWS regions with a single command. This package adds region-aware deployment tooling, letting you run assets, queues, and environments in several regions for lower latency and better resilience.
Prerequisites. You need a working Laravel + Vapor setup first: a Vapor account, an AWS account linked to it, the vapor-cli binary installed and authenticated (vapor login), and a vapor.yml that already deploys one environment successfully. As of v1.2.0 the package targets Laravel 10; if you are on Laravel 11/12 the release notes say nothing, so treat that as untested territory. This package is a thin orchestration layer on top of Vapor anyway, so any existing Vapor misconfiguration will simply be multiplied by the number of regions you target.
Install. It is a deploy-time tool, not a runtime dependency:
composer require --dev thebytelab/laravel-vapor-multi-region-deploy:^1.2
Laravel package auto-discovery registers the service provider. Confirm the command exists before doing anything else:
php artisan list | grep -i vapor
php artisan help <command-name>
Where to look first.
vendor/thebytelab/laravel-vapor-multi-region-deploy/src/Console/ — the command class is small and tells you exactly what it shells out to or writes into vapor.yml.php artisan vendor:publish --provider="TheByteLab\..." (check the README for the tag). If no config is published, region lists are almost certainly coming from vapor.yml or command options.First use case. Do not start with production. Pick staging, add a second region block to vapor.yml, and run the command against staging only. Verify:
vapor env / Vapor dashboard shows both)..env/secrets exist in both region environments.Only after that should you touch production, and even then run it once manually before wiring it into CI.
Region definition lives in vapor.yml. The package does not invent a parallel config format; you declare one environment per region (or the command duplicates/overrides for you). The common shape is:
environments:
production-us:
region: us-east-1
# ...
production-eu:
region: eu-west-1
# ...
If the command accepts a region list option, prefer that over hand-maintaining N duplicate blocks, but keep vapor.yml as the source of truth so a plain vapor deploy still works for a single region.
CI/CD fan-out. The real value is in pipelines. Do not deploy regions in parallel — Vapor's API and Lambda concurrency limits will bite you. Serial is fine:
# .github/workflows/deploy.yml
- name: Deploy to all regions
env:
VAPOR_API_TOKEN: ${{ secrets.VAPOR_API_TOKEN }}
run: |
php artisan <multi-region-command> production \
--regions=us-east-1,eu-west-1 \
--no-interaction
Keep the git SHA identical across regions so rollbacks stay coherent, and gate the step behind the same tests you already run for single-region deploys.
Traffic steering is not included. This package ships code to N regions; it does not route users to the nearest one. You still need Route 53 latency-based or failover records, or a CloudFront distribution with one origin per region and origin failover. Treat the package as deploy tooling and build the routing layer separately.
Per-region state is the design. Each Vapor environment gets its own S3 assets bucket, its own SQS queues, its own secrets, its own database. Decide deliberately:
Makefile / composer script wrapper. Because the command is obscure, wrap it once so the team never types it directly:
deploy-multi:
php artisan <multi-region-command> production --regions=$$REGIONS --no-interaction
Then REGIONS can differ between local and CI without editing the command.
Migrations. Vapor runs migrations on deploy per environment. That means your migrations execute N times — once per regional database. This is correct if the databases are independent and the migrations are idempotent; it is catastrophic if they somehow point at one shared database.
Laravel version support is a moving target. v1.2.0 explicitly adds Laravel 10 support, which tells you the 1.x line is being kept alive for L10 apps — but there is still no signal for Laravel 11/12. If you upgrade the framework before the package catches up, you will likely find out at composer update time (constraint conflict) rather than at deploy time. Pin the major and read the release notes on every bump.
Secrets and environment variables drift. Every region is a separate Vapor environment. Add a variable in production-us and forget production-eu, and you get a half-broken fleet with no warning. Add a post-deploy assertion that both environments report the same non-secret env keys, or drive secrets from a committed manifest and loop over regions.
Domains and certificates are per environment. Vapor provisions an ACM certificate and domain binding for each environment. A custom domain therefore needs either a separate subdomain per region or a Route 53 record set that abstracts them. Plan DNS before your first multi-region deploy — retrofitting it later means re-pointing live traffic.
No runtime failover, no health checking. Nothing here detects a dead region. If that is what you actually want, you are looking for Route 53 failover with health checks or CloudFront origin failover — this package will not do it.
Rollbacks are per region. vapor rollback operates on one environment. If region A deploys fine and region B fails, you have a version skew across your fleet and a manual cleanup. Either make the command fail closed (deploy canaries first, abort the whole run on first error) or accept that partial deploys require manual reconciliation.
Check whether it mutates vapor.yml. If the command rewrites the file temporarily to inject regions, a dirty working tree or an interrupted run can leave generated blocks behind. Make sure git status is clean before running in CI, and never commit the mutated file.
Vapor CLI version compatibility. The 1.x line predates the current vapor-cli and was validated against the CLI of late 2023; a Laravel 10 bump does not obviously change that. If you are on a newer vapor-cli major version, smoke-test in a throwaway Vapor project first. The surface area is small — if it breaks, forking and patching the command class is a realistic option and probably faster than waiting for a release.
Debugging. Run with -vvv and watch the raw output of whatever the package shells out to. Vapor's own logs live under ~/.vapor, and the Vapor dashboard shows per-environment deploy state — when the aggregate command reports success but something is wrong, go region-by-region in the dashboard rather than trusting the wrapper's exit code.
Guard non-production environments. Add an if (app()->isLocal()) return;-style check or exclude the command from local usage entirely. Accidentally triggering a multi-region deploy from a developer laptop against production credentials is an avoidable incident.
Pin the version. With a single maintainer and a very small user base, treat this as vendored code: pin ^1.2 (or an exact 1.2.*) and review the diff on every bump. The Laravel 10 release is a good reminder that framework-support bumps arrive on the maintainer's schedule, not yours.
How can I help you explore Laravel packages today?