laravel → aws · 2026 migration playbook

Migrate a Laravel app to AWS — the architecture, the queues, the cutover, and who runs it for you.

Laravel is a joy to build in and fiddly to run well once Forge, a single VPS, or a shared host stops being enough. This is the senior-engineer playbook for putting a production Laravel/PHP app on AWS: the target architecture (PHP-FPM + nginx on ECS/Fargate or App Runner, RDS/Aurora MySQL, ElastiCache for cache/sessions/queues, S3 via Flysystem, behind an ALB), Horizon workers and the scheduler done the AWS way, .env → Secrets Manager, the MySQL cutover, and the gotchas. A MAP-funded AWS partner can run the whole thing — often at little-to-no cost to you.

cutover downtime
0–15 min
project length
3–7 weeks
queue model
Horizon on ECS
cost to you (MAP)
$0–low
TL;DR
  • Laravel maps cleanly onto AWS once you accept one structural fact: a request is served by PHP-FPM behind nginx, so the container story is the two-process PHP-FPM + nginx pattern. Web traffic lands on ECS on Fargate (or App Runner for the simplest path, or EC2 for full host control) behind an Application Load Balancer.
  • The supporting services map almost one-to-one: MySQL → Amazon RDS or Aurora MySQL; cache, sessions, and the queue backend → Amazon ElastiCache (Redis/Valkey); file storage → Amazon S3 via Laravel's Flysystem driver; Horizon workers → a dedicated ECS service; the scheduler → Amazon EventBridge Scheduler invoking `schedule:run`; and `.env` → AWS Secrets Manager + SSM Parameter Store, injected as environment variables.
  • The risky part is the database cutover, and it is solvable: AWS Database Migration Service (DMS) keeps RDS/Aurora MySQL continuously synced (CDC) with your current MySQL while you test, then a short maintenance/DNS switch (typically 0–15 minutes) flips traffic. CloudRoute routes you to a vetted AWS partner who runs it end-to-end — and when the workload qualifies for the AWS Migration Acceleration Program (MAP), AWS funds the migration and the customer pays little-to-nothing.
the trigger

IWhy teams move Laravel onto AWS — and what actually changes

Most Laravel apps start on something simple — Forge driving a single VPS, a managed PHP host, or one hand-built EC2 instance. Teams move to a real AWS architecture when that single box becomes the bottleneck, the single point of failure, or the thing that cannot pass a security review.

The first trigger is scale and availability. A single VPS runs the web server, the queue workers, the scheduler, and often MySQL and Redis all on one host — fine until one traffic spike, one runaway Horizon job, or one failed disk takes everything down. On AWS, web traffic runs as stateless containers behind an Application Load Balancer across two or more Availability Zones, the database is a managed RDS/Aurora instance with automated backups and Multi-AZ failover, and the queue workers scale independently of the web tier. Nothing in Laravel changes conceptually — you are separating processes that were sharing one box.

The second trigger is compliance. A SOC 2 or ISO audit wants encrypted-at-rest databases, secrets that are not sitting in a plaintext `.env` on a shared host, network isolation, audit logging, and least-privilege access — all of which AWS provides as primitives (RDS encryption, Secrets Manager, VPC, CloudTrail, IAM) and a hand-managed VPS makes you build or fake. The honest counterpoint: Forge-on-a-VPS is simpler to operate, and AWS asks you to own more — a landing zone, IAM, networking, container images, and the PHP-FPM + nginx packaging Forge did invisibly. That operational surface is precisely why most teams do not run this migration alone — the CloudRoute angle is that a vetted AWS partner runs it for you, often funded by AWS.

what does NOT change

Your Laravel code barely moves. MySQL stays MySQL (RDS/Aurora), Redis stays Redis (ElastiCache), S3 was already an S3 target if you used the s3 driver, and Eloquent, your migrations, your queued jobs, and Horizon are unchanged. The work is packaging and wiring — Dockerizing PHP-FPM + nginx, moving .env into Secrets Manager, and splitting web / worker / scheduler into separate services — not rewriting the app.

where things land

IIThe target architecture: PHP-FPM + nginx, queues, scheduler, data

There is no single "AWS version of Forge," but Laravel's shape maps onto AWS cleanly once you separate the three runtime roles — web, queue workers, scheduler — and pick a compute target. The data and supporting services map almost one-to-one.

For compute, there are three realistic targets — Amazon ECS on Fargate (the workhorse: serverless containers, VPC control, independent web + worker services, an ALB in front, and no host to manage), AWS App Runner (the closest thing to Forge: point it at an image and it serves HTTPS and autoscales), and EC2 (full host control or a lift-and-shift). The callout below picks between them. The web tier is the one Laravel-specific wrinkle: a request is handled by PHP-FPM with nginx in front, so on AWS this becomes a two-container ECS task (nginx + PHP-FPM sharing the task, nginx proxying to 127.0.0.1:9000) — the pattern most partners standardize on — with the ALB terminating TLS via a free ACM certificate.

For data, MySQL → Amazon RDS for MySQL (like-for-like managed MySQL) or Aurora MySQL (AWS's MySQL-compatible engine — a little more per hour, but faster failover, autoscaling storage, up to 15 read replicas, and Serverless v2 capacity scaling). Because both speak MySQL, Eloquent, your migrations, and your queries are unchanged — you swap DB_HOST and migrate the data. Amazon ElastiCache (Redis OSS or Valkey) takes over everything Redis did on the VPS at once — cache (CACHE_STORE=redis), sessions (SESSION_DRIVER=redis), and the queue backend (QUEUE_CONNECTION=redis) Horizon consumes — one managed cluster, three jobs, a connection-string change. File storage stays on Amazon S3 via Laravel's Flysystem s3 driver; if you wrote uploads to local disk, that becomes the single most important code change, because the container filesystem is ephemeral.

For the two background roles: Horizon runs as its own ECS service (command php artisan horizon), scaling on queue depth rather than web traffic. The Laravel scheduler (the single schedule:run crontab line) becomes an Amazon EventBridge Scheduler rule firing every minute to run a one-off ECS task that calls schedule:run — covered in detail next. Outbound email keeps working through Laravel's mail config; move to Amazon SES or keep the vendor billed directly.

Fargate vs App Runner vs EC2 — pick based on control

App Runner for the simplest Forge-like web tier when you want git-push/image-push simplicity (least new surface; you still run Horizon + scheduler elsewhere). ECS on Fargate when you want coordinated web + Horizon-worker + scheduler services, VPC networking control, and fine-grained autoscaling — the most common landing spot for "we outgrew Forge/the VPS." EC2 when you want full host control or are lift-and-shifting an existing server layout before modernizing.

the hands-on part

IIIDockerizing Laravel: PHP-FPM + nginx, and config → Secrets Manager

The most hands-on task in a Laravel→AWS move is turning a Forge/VPS deployment into a container image and moving the flat `.env` into managed config — mechanical, but where PHP teams without container experience slow down.

On a VPS, Forge installs PHP and the right extensions, runs composer install, builds assets, and points nginx at public/index.php. On AWS you reproduce that in a Dockerfile: a build stage runs composer install --no-dev --optimize-autoloader and your asset build (npm ci && npm run build), then a runtime stage on a slim php-fpm base image installs the extensions your app uses — typically pdo_mysql, bcmath, gd or imagick, redis (via PECL), intl, zip, and opcache — copies the app, and runs the production cache commands (config:cache, route:cache, view:cache, event:cache). The nginx container is a standard image whose server block proxies PHP requests to PHP-FPM over FastCGI on port 9000.

The same image serves all three roles — you change the container command, not the image: the web service runs PHP-FPM (fronted by nginx), the Horizon service runs php artisan horizon, and the scheduler task runs php artisan schedule:run. Database migrations become a one-off task at deploy time (migrate --force as an ECS run-task or pipeline step) — never on container boot, so two tasks starting at once cannot race to migrate the same database. And enable OPcache for production, which means a deploy ships a fresh image rather than editing files in place.

Config is the other half. Laravel reads config from environment variables, so the goal is to supply the same variables the app expects — without shipping an `.env` file. Split it by sensitivity: real secrets (APP_KEY, DB_PASSWORD, API keys, mail credentials) into AWS Secrets Manager; non-sensitive config (APP_ENV, APP_URL, CACHE_STORE, QUEUE_CONNECTION) into SSM Parameter Store. The ECS task definition references both and injects them as environment variables before the container starts — so every env()/config() call behaves as it did on the VPS. The migration step is a one-time export, a sort into secret-vs-config, and a load, scripted so nothing leaks into an image layer.

the APP_KEY trap

The most common "it works locally but sessions break on AWS" bug is an APP_KEY mismatch across tasks. APP_KEY encrypts sessions, cookies, and signed URLs: generate it once, store it in Secrets Manager, and inject the same value into every task. Rotating it logs everyone out — treat it like the encryption key it is.

background work

IVQueue workers (Horizon) and the scheduler, the AWS way

The piece most likely to be set up casually on a VPS — and to break quietly after a migration — is background work. Laravel's queue + Horizon and the scheduler each get a clean, isolated home on AWS.

On a VPS, Supervisor keeps php artisan horizon alive and a crontab line runs schedule:run every minute — both sharing the box with web traffic. On AWS, the Horizon workers become a dedicated ECS service running php artisan horizon, consuming the same Redis queues now backed by ElastiCache. Because it is its own service, it scales on queue depth independently of the web tier, and ECS restarts a crashed worker the way Supervisor used to — across AZs and without a host to babysit. (If you do not need Horizon's dashboard, Laravel also supports Amazon SQS as a fully-managed queue connection; most teams keep Redis + Horizon through the migration and consider SQS later for high-throughput queues.)

The scheduler is the subtle one. Laravel's design is a single per-minute invocation of schedule:run, which then decides which commands are due — so you must run it exactly once a minute, not once per web task. The AWS-native answer is an EventBridge Scheduler rule on a one-minute schedule that triggers a single one-off ECS task running schedule:run. That guarantees one invocation regardless of how many web containers are running — avoiding the trap of baking the cron into the web image and firing every scheduled job N times. Long-running scheduled work should dispatch a queued job so the invocation stays fast. Either way, the queue and scheduler are now isolated infrastructure, not processes fighting your web server for CPU.

the lookup table

VLaravel → AWS component map (the principles behind the table)

The full row-by-row mapping — every Laravel building block, its AWS service, what changes, and the effort — lives in the comparison table below. Two principles make reading it safe.

First, anything that speaks a standard protocol moves with a config change and no rewrite: MySQL → RDS/Aurora MySQL, Redis (cache/session/queue) → ElastiCache, and S3 via the Flysystem s3 driver — the "trivial / low-effort" rows, where you change DB_HOST, REDIS_HOST, and the S3 credentials. Second, anything that was a host-level convention needs a one-time translation into an AWS-native primitive: the Forge/nginx + PHP-FPM setup → a Dockerfile + ECS task, `.env` → Secrets Manager + Parameter Store, the Supervisor worker → a Horizon ECS service, the crontab → EventBridge Scheduler, TLS/domains → Route 53 + ACM. Done once and documented, that is the "Medium" work a partner does for you.

The one row that is genuinely application work rather than config is local-disk storage → S3: if any part of the app wrote files to the local filesystem (avatars, generated PDFs, temp exports), that code must move to Storage::disk('s3') before cutover, because the container filesystem is ephemeral and shared by nothing. Usually small and well-contained — but it has to be found, not assumed, which is what the Assess phase is for.

the risky 20 minutes

VIThe MySQL cutover: DMS, DNS, and a short downtime window

Everything else — containers, the landing zone, ElastiCache, Horizon, the scheduler — can be built and tested without touching production. The MySQL cutover is the one moment that touches live data, and where a plan earns its keep. Done right, user-visible downtime is zero to fifteen minutes.

The core technique is to keep the new RDS/Aurora MySQL database continuously in sync with your current MySQL while you test, so that at cutover you switch to an already-current copy rather than dumping and loading a database under time pressure. AWS Database Migration Service (DMS) does exactly this: a full load into RDS/Aurora MySQL, then a switch into change data capture (CDC) mode that streams every subsequent insert/update/delete in near-real time by reading the source MySQL binary log. Because both ends are MySQL, this is a homogeneous migration — no Schema Conversion Tool needed; the schema moves as-is. (Binary logging on the source is the one prerequisite to confirm in the Assess phase.)

With CDC running and the new stack smoke-tested against the synced database, the cutover is short and scripted: maintenance mode (php artisan down) → drain the last few seconds of CDC → flip DB_HOST and switch traffic to the new service → update the Route 53 record (TTL lowered ahead) → a final migrate --force if pending → verify writes land in RDS → bring the app up. Because the data was already synced, the window is dominated by DNS propagation and verification, not data transfer — commonly 0–15 minutes of write-downtime during a low-traffic period.

The rollback plan is non-negotiable and simple: keep the old environment running until you are confident, and if something is wrong, switch DB_HOST and DNS back. The clean window is before RDS has accepted production writes the old database hasn't seen — so keep the rollback window short and watch closely. Lowering DNS TTL to 60 seconds a day ahead makes both the switch and the rollback fast.

why DMS over a cold mysqldump

A cold mysqldump | mysql makes your downtime window = export + transfer + import of the whole database: 20–60 minutes for 5GB, unacceptable at 50GB+. DMS with CDC moves the bulk load before the window and only drains the last few seconds during it — so downtime stays in single-digit minutes regardless of database size. The one prerequisite: binary logging enabled on the source MySQL.

the runbook

VIIThe step-by-step migration (assess → land → cut over → optimize)

Here is the end-to-end sequence a partner runs, mapped to the AWS MAP phases (Assess → Mobilize → Migrate). For a typical Laravel app this is a 3–7 week project — mostly parallelizable, none of it touching production until the final cutover.

  • 1 — Assess (days 1–5) — Inventory the runtime: PHP version + extensions, every queued job, every scheduled command, the `.env` contents, the database size + binary-log config, and any code that writes to local disk. Decide Fargate vs App Runner vs EC2 and RDS vs Aurora MySQL; produce the target architecture and a cost model. Under MAP this Assess/TCO phase is typically free.
  • 2 — Build the landing zone — Stand up the AWS account structure, VPC, subnets, security groups, IAM roles, ECR, and Secrets Manager / Parameter Store. (Reuses the AWS Landing Zone and AWS DevOps foundations in the DevOps cluster.)
  • 3 — Containerize + move config — Write the PHP-FPM + nginx Dockerfile (web, Horizon, and scheduler as one image with three commands), load `.env` into Secrets Manager + Parameter Store (APP_KEY once, shared everywhere), and switch the filesystem to the S3 disk.
  • 4 — Provision data + cache — Create the RDS/Aurora MySQL instance and the ElastiCache cluster in the VPC, create the schema, point cache + sessions + queue at ElastiCache, and wire EventBridge Scheduler for schedule:run.
  • 5 — Replicate + smoke-test — Run a DMS full load from the current MySQL into RDS/Aurora, then switch to CDC so the new database tracks production. Deploy the web + Horizon services against the synced database (no public traffic) and run the full suite + manual tests, including queued jobs, scheduled commands, and S3 uploads.
  • 6 — Cut over — Maintenance mode → drain CDC → flip DB_HOST → update Route 53 (low TTL pre-set) → final migrate --force if pending → verify writes land in RDS → bring the app up. Target window: 0–15 minutes.
  • 7 — Optimize + decommission — Apply a Compute Savings Plan, right-size Fargate and RDS, set autoscaling, confirm CloudWatch alarms and backups. Keep the old environment as rollback for a short window, then turn it off — that decommission is when the savings become real.
what bites teams

VIIIGotchas: the Laravel-specific things that turn a clean migration messy

Most Laravel→AWS migrations that go badly go badly for a small, repeatable set of PHP-specific reasons. Naming them up front is the cheapest insurance there is.

  • Local-disk writes break across tasks — Files written to the container filesystem (uploads, generated PDFs) survive on a single VPS by luck, are wiped on every deploy, and are invisible to other web tasks. Audit for local file writes in the Assess phase and move them to the S3 disk before cutover.
  • APP_KEY mismatch logs everyone out — A different (or freshly generated) APP_KEY per task breaks sessions, encrypted cookies, and signed URLs. Generate it once, store it in Secrets Manager, inject the same value into every task.
  • The scheduler runs N times — Bake the crontab into the web image and every scheduled job fires once per web container. Run schedule:run exactly once a minute via EventBridge Scheduler → a single ECS task. (Same trap for sessions: SESSION_DRIVER=file logs users out at random behind a load balancer — move sessions to Redis.)
  • Missing PHP extension at runtime — The app booted on the VPS because the host had imagick / intl / gd / redis. The slim php-fpm base image does not — a classic "works locally, 500s on AWS." Inventory the extensions the app loads and install exactly those in the Dockerfile.
  • MySQL binary logging not enabled — DMS CDC reads the source binary log; if binlog is off or the wrong format, continuous replication can't run and you're forced into a cold dump. Confirm it in the Assess phase, before the cutover is scheduled.
  • Forgetting to decommission the old box — Savings and the security win are not real until the old VPS and its database are off. Keep it as rollback for a defined short window — then actually shut it down.
component-by-component

Laravel component → AWS service (what changes + effort)

The definitive lookup: every Laravel building block, where it lands on AWS, what changes, and the effort. "Trivial / Low" rows are config swaps; "Medium" rows are the real packaging work — and the work a partner does for you.

Laravel componentAWS serviceWhat changesEffort
HTTP app (PHP-FPM)ECS/Fargate or App Runner (or EC2) + ALBForge/nginx setup → PHP-FPM + nginx containerMedium
Web server (nginx)nginx container in the task + ALB (TLS via ACM)Server block proxies FastCGI to PHP-FPM:9000Low
MySQL databaseAmazon RDS for MySQL / Aurora MySQLSwap DB_HOST; data cutover via DMSMedium (cutover)
Cache store (Redis)Amazon ElastiCache (Redis / Valkey)Connection string only (CACHE_STORE=redis)Trivial
SessionsElastiCache (Redis) — SESSION_DRIVER=redisMove off file/local driver to RedisLow
Queue backendElastiCache (Redis) for Horizon, or Amazon SQSQUEUE_CONNECTION → Redis/SQSLow
Queue workers (Horizon)Dedicated ECS service (php artisan horizon)Supervisor → ECS service autoscaling on queue depthMedium
Scheduler (schedule:run)EventBridge Scheduler → one-off ECS taskCrontab line → one invocation/min, never per web taskLow
File storage (Flysystem)Amazon S3 (s3 driver)Local-disk writes → Storage::disk('s3')Low–Medium
.env configurationSecrets Manager + SSM Parameter StoreSplit secret vs config; inject to the taskLow
Outbound emailAmazon SES (or vendor direct)Swap mailer config / SMTP credentialsLow
DB migrationsECS run-task / CodeBuild step (migrate --force)Run once at deploy, not on container bootLow
Deploys (Forge/Envoyer)CodePipeline + CodeBuild + ECR (or GitHub Actions)Build image, push to ECR, update ECS serviceMedium
Custom domain + SSLRoute 53 + ACM (free TLS)DNS + cert on ALB / App RunnerLow
Effort levels are representative. The Medium rows — PHP-FPM + nginx containerization, the MySQL cutover, the Horizon service, the CI/CD flow — are exactly what a MAP-funded partner handles end-to-end so your team keeps shipping features.
want this run for you — and funded?
Get matched with an AWS partner who runs your Laravel migration (often MAP-funded)
Start in 3 minutes →
a recent match

A Laravel→AWS migration CloudRoute routed — anonymized

inquiry · series-a b2b saas (laravel), Lisbon
Series-A B2B SaaS on a Laravel monolith (Laravel 11, PHP 8.3), deployed by Laravel Forge to two DigitalOcean droplets — one running nginx + PHP-FPM, one running MySQL + Redis + Supervisor-managed Horizon, with a crontab scheduler. ~$650/month in droplets, but failing an enterprise prospect's security review on encryption-at-rest, secrets handling, and single-AZ availability.

Situation: The blocker was not cost — it was a stalled enterprise deal. The prospect's security questionnaire required encrypted-at-rest databases, secrets not stored in a plaintext .env on a shared host, network isolation, and no single point of failure. The three-person team had deep Laravel experience but had never run AWS, ECS, or a multi-AZ architecture, and could not risk a hand-rolled migration mid-sales-cycle.

What CloudRoute did: Routed within 24 hours to an AWS Advanced-tier partner with a Laravel track record, who ran the MAP Assess phase (free) and filed the work as a MAP engagement. Target: ECS on Fargate across two AZs (a PHP-FPM + nginx web service behind an ALB, a dedicated Horizon service), Aurora MySQL with Multi-AZ and encryption-at-rest, ElastiCache for cache + sessions + the Horizon queue, S3 via Flysystem (a few local-disk avatar writes moved to the s3 disk), .env split into Secrets Manager and Parameter Store, EventBridge Scheduler for schedule:run, and GitHub Actions → ECR → ECS with migrations as a deploy-time run-task. MySQL moved via AWS DMS (full load + CDC).

Outcome: Cutover ran in a Sunday-night window with ~9 minutes of write-downtime — DMS had Aurora fully in sync, so the switch was DB_HOST + DNS + verification, not data transfer. The architecture cleared every item on the security questionnaire (encryption-at-rest, Secrets Manager, multi-AZ, CloudTrail), and the enterprise deal closed six weeks later. Project ran ~5 weeks. Because the workload qualified for MAP, AWS funded the assessment and credited the migration cost — out-of-pocket migration cost was effectively $0, and CloudRoute's commission came from the partner via MAP.

project length: ~5 weeks · cutover downtime: ~9 min · security review: passed · migration cost to customer: ~$0 (MAP-funded)

faq

Common questions

What is the best way to host a Laravel app on AWS?
For most production Laravel apps, the best target is Amazon ECS on Fargate: run PHP-FPM + nginx as a container task behind an Application Load Balancer across two Availability Zones, with a separate ECS service for Horizon workers. Use Amazon RDS for MySQL or Aurora MySQL for the database, Amazon ElastiCache (Redis) for cache, sessions, and the queue, and Amazon S3 (via Flysystem) for file storage. For the simplest Forge-like web tier, AWS App Runner is a faster path; for full host control or a lift-and-shift, EC2 is the option.
How do I run Laravel queues and Horizon on AWS?
Run Horizon as its own ECS service whose container command is `php artisan horizon`, consuming Redis queues backed by Amazon ElastiCache. Because it is a separate service, it scales on queue depth independently of web traffic and ECS restarts it if it crashes — replacing Supervisor. You can alternatively use Amazon SQS as Laravel's queue connection (fully managed), but that drops Horizon's dashboard, so most teams keep Redis + Horizon through the migration.
How does the Laravel scheduler work on AWS without a crontab?
Laravel's scheduler is a single per-minute invocation of `php artisan schedule:run`, which then dispatches whichever commands are due. On AWS, create an Amazon EventBridge Scheduler rule on a one-minute schedule that triggers a single one-off ECS task (or a thin Lambda) running `schedule:run`. The critical detail is running it exactly once a minute — not once per web container — so do not bake the cron into the web image, or every scheduled job fires N times.
How do I migrate the MySQL database with minimal downtime?
Use AWS Database Migration Service (DMS). It does a full load of your current MySQL into Amazon RDS or Aurora MySQL, then switches to change data capture (CDC), streaming ongoing changes from the source binary log in near-real time. You test the new stack against this continuously-synced database, then cut over in a short window: drain the last few seconds, switch DB_HOST and DNS, verify, and bring the app up. Because both ends speak MySQL it is a homogeneous migration (no Schema Conversion Tool), and downtime is typically 0–15 minutes regardless of database size. The one prerequisite is binary logging enabled on the source.
How do I handle the .env file and APP_KEY on AWS?
Do not ship an .env file in the image. Split it by sensitivity: real secrets (APP_KEY, DB_PASSWORD, API keys, mail credentials) go into AWS Secrets Manager; non-sensitive config (APP_ENV, APP_URL, CACHE_STORE, QUEUE_CONNECTION) goes into SSM Parameter Store. The ECS task definition references both and injects them as environment variables, so Laravel reads config as before. The key detail is APP_KEY: generate it once, store it in Secrets Manager, and inject the same value into every task — a mismatch breaks sessions, encrypted cookies, and signed URLs.
Does my Laravel code need to change to run on AWS?
Very little. MySQL stays MySQL (RDS/Aurora), Redis stays Redis (ElastiCache), and your queues, Horizon, Eloquent, and migrations are unchanged — those are config swaps. The work is packaging and wiring: Dockerizing PHP-FPM + nginx, installing the right PHP extensions, moving .env into Secrets Manager, and splitting web / Horizon / scheduler into separate services. The one piece of genuine code work is any logic that writes to the local filesystem — uploads or generated files must move to the S3 disk (Storage::disk('s3')), because the container filesystem is ephemeral and not shared across tasks.
What does AWS MAP funding mean for the cost of the migration?
The AWS Migration Acceleration Program (MAP) is how the migration itself can cost little to nothing. For qualifying migrations — generally those with a meaningful projected AWS spend afterward — AWS funds the Assess phase (typically free) and credits a large share of the migration/modernization cost, paying the partner through MAP rather than you. When a workload does not qualify, CloudRoute still routes you to a vetted partner who runs the cutover at a fixed scope, de-risking the riskiest part of the project.
How long does a Laravel to AWS migration take?
For a typical Laravel app — a web tier, Horizon workers, a scheduler, MySQL, Redis, and S3 — a partner-run migration is usually 3–7 weeks end-to-end. Most of that is building and testing the landing zone, the PHP-FPM + nginx containers, and the synced database in parallel, without touching production; only the final cutover (a single short maintenance window) touches live traffic.

Put your Laravel app on AWS — run by a partner, often funded by AWS.

CloudRoute routes you to a vetted AWS partner who plans and runs the whole Laravel→AWS migration — the PHP-FPM + nginx containers, RDS/Aurora MySQL, ElastiCache for cache/sessions/queues, Horizon workers, the scheduler, the DMS cutover, and the cost optimization. Qualifying migrations are MAP-funded, so you get a production-grade, multi-AZ AWS architecture without paying the usual migration bill.

matched within< 24h
cutover downtime0–15 min
migration cost (MAP)$0–low
Migrate a Laravel App to AWS — architecture, queues & cutover (2026) · CloudRoute