laravel → aws · 2026 migration playbook

Migrate a Laravel app to AWS: architecture, queues, the scheduler and the cutover.

Laravel on AWS usually means nginx plus PHP-FPM in containers on ECS with Fargate, MySQL on RDS or Aurora, ElastiCache for cache, sessions and Horizon queues, S3 for files, and EventBridge Scheduler running the Laravel scheduler once a minute. Your Eloquent models and jobs do not change. The work is packaging, configuration and a careful MySQL cutover.

web tier
nginx + PHP-FPM on Fargate
code changes
config, not logic
TL;DR
  • Web traffic runs as a two-container ECS task (nginx in front of PHP-FPM) on Fargate behind a load balancer. MySQL moves to RDS or Aurora MySQL. ElastiCache (Redis OSS or Valkey) takes cache, sessions and the queue Horizon reads. Files go to S3 through the Flysystem s3 driver.
  • The Laravel-specific work: a Dockerfile with the PHP extensions you use, .env values moved into Secrets Manager and Parameter Store, Horizon as its own ECS service, and the scheduler as one EventBridge Scheduler rule per minute (not cron inside every web container). One APP_KEY for every task.
  • The MySQL cutover is the risky part; AWS DMS can keep RDS in sync so the switch is short. A vetted AWS partner can run it. MAP is built for migrations with meaningful ongoing AWS spend, so a single small app may not qualify; when the migration does, your matched partner files it: typically $50K to $150K for startups. Depends on the workload; AWS approves.
the trigger

IWhy teams move Laravel onto AWS, and what changes

Most Laravel apps start on Forge driving one VPS, a managed PHP host or a single EC2 instance. Teams move when that box becomes the bottleneck, the single point of failure, or fails a security review.

Scale and availability. One VPS runs web, queue workers, the scheduler and often MySQL and Redis. On AWS the web tier runs as stateless containers across Availability Zones, the database is managed with Multi-AZ failover, and workers scale on their own.

Compliance. Audits want encrypted databases, secrets that are not in a plaintext .env, network isolation, audit logs and least-privilege access. AWS provides these as building blocks (RDS encryption, Secrets Manager, VPC, CloudTrail, IAM).

The counterpoint: Forge on a VPS is simpler to run, and AWS asks you to own more. That is why many teams have a partner run the move.

what does not change

MySQL stays MySQL, Redis stays Redis, and S3 was already a target if you used the s3 driver. Eloquent, migrations, queued jobs and Horizon are unchanged. The work is packaging and wiring, not rewriting the app.

where things land

IIThe target architecture

Separate the three runtime roles (web, queue workers, scheduler), pick a compute target, and the data services map almost one-to-one.

Compute. Amazon ECS on Fargate is the usual home: web and Horizon as separate services, VPC control and autoscaling, no host to patch. The web task runs nginx and PHP-FPM side by side, with nginx proxying to 127.0.0.1:9000 and the load balancer terminating TLS with an ACM certificate. EC2 suits a lift-and-shift of an existing server layout. (App Runner closed to new customers on April 30, 2026; ECS Express Mode is AWS's simpler container option now.)

Data. RDS for MySQL (like-for-like) or Aurora MySQL (storage that grows on its own, faster failover, up to 15 readers). You change DB_HOST and move the data. ElastiCache covers cache (CACHE_STORE=redis), sessions (SESSION_DRIVER=redis) and queues (QUEUE_CONNECTION=redis) in one cluster. Files go to S3; anything written to local disk must move to Storage::disk('s3'), because container disks are ephemeral.

the hands-on part

IIIDockerizing Laravel, and moving .env into AWS

You reproduce what Forge did invisibly in a Dockerfile, and supply the same environment variables without shipping a .env file.

A build stage runs composer install --no-dev --optimize-autoloader and your asset build; a runtime stage on a slim php-fpm image installs the extensions you use (often pdo_mysql, bcmath, gd or imagick, redis, intl, zip, opcache) and runs config:cache, route:cache, view:cache and event:cache. The same image serves every role: PHP-FPM for web, php artisan horizon for workers, php artisan schedule:run for the scheduler task.

Run migrate --force as a one-off task at deploy time, never on container boot. Put real secrets (APP_KEY, DB_PASSWORD, API keys) in AWS Secrets Manager and plain config (APP_ENV, APP_URL, drivers) in SSM Parameter Store; the ECS task definition injects both as environment variables.

the APP_KEY trap

APP_KEY encrypts sessions, cookies and signed URLs. Generate it once, store it in Secrets Manager and inject the same value into every task. A mismatch logs users out at random; rotating it logs everyone out.

background work

IVHorizon and the scheduler, the AWS way

Background work is set up casually on a VPS and breaks quietly after a migration. Give each part its own home.

Horizon becomes a dedicated ECS service running php artisan horizon against ElastiCache, scaling on queue depth and restarted by ECS if it crashes, as Supervisor did. Laravel also supports Amazon SQS as a managed queue connection if you do not need Horizon's dashboard.

The scheduler must run schedule:run exactly once a minute. The AWS-native answer is one EventBridge Scheduler rule that starts a one-off ECS task each minute. Baking cron into the web image fires every scheduled job once per web task. Long-running scheduled work should dispatch a queued job.

the risky part

VThe MySQL cutover: DMS, DNS and a short window

Containers, the landing zone and S3 can be built and tested without touching production. The database cutover is the one moment that touches live data.

AWS DMS does a full load into RDS or Aurora MySQL, then streams ongoing changes from the binary log, so at cutover you switch to an already-current copy. CDC needs binary logging enabled in row format on the source; check that early. Without it, or for a small database, use mysqldump and restore inside a maintenance window and time a test run first.

The cutover: maintenance mode, let DMS drain, pause the scheduler rule and let Horizon finish, switch DB_HOST and Redis settings, update Route 53 (TTL lowered a day ahead), check that writes land in RDS, leave maintenance. Keep the old server as a rollback until you are confident.

who runs it, who funds it

VIWho runs the move, and who can fund it

You can do this yourself with the steps above. Many teams have a partner run the landing zone, the containers and the cutover.

Partner-filed funding: AWS says the Migration Acceleration Program (MAP) helps offset initial migration costs. It is built for migrations with meaningful ongoing AWS spend, so a single small Laravel app may not qualify. When the migration does qualify, your matched partner files it and AWS approves: typically $50K to $150K for startups. Depends on the workload; AWS approves. Activate credits are separate, and you apply for those yourself.

CloudRoute matches you with one vetted AWS partner. Startups pay CloudRoute nothing; partners pay CloudRoute a monthly membership plus 10% of AWS-approved funding.

Who files it
FundingWho files itAmountWhen it fits
Migration Acceleration Program (MAP)Your matched AWS partner$50K to $150K for startups. Depends on the workload; AWS approves.You are not on AWS yet and want to migrate.
AWS Activate FoundersFounder applies$1,000 to start, up to $5,000Self-funded startups with no investor or accelerator behind them.
AWS Activate PortfolioFounder appliesup to $200,000Startups backed by a VC firm, accelerator or angel investor that is an AWS Activate Provider.
Facts checked on October 10, 2026. AWS decides every application.
what bites teams

VIILaravel-specific gotchas

The small set of things that turn a clean migration messy.

  • Local-disk writes break across tasks: Uploads, generated PDFs and temp exports written to local disk disappear or diverge across containers. Move them to S3 before cutover.
  • APP_KEY mismatch: Different keys across tasks break sessions and signed URLs. One key, from Secrets Manager, everywhere.
  • The scheduler runs N times: Cron inside the web image fires once per task. Use one EventBridge Scheduler rule.
  • Missing PHP extension: An extension Forge installed and your Dockerfile did not shows up as a runtime error. List extensions from the old server first.
  • MySQL binary logging off: DMS change data capture needs row-format binary logging on the source. Without it, plan a dump and restore window.
  • Forgetting to shut the old box down: Keep it as a fallback for a defined short window, then turn it off.
component by component

Laravel component to AWS service

Every Laravel building block, where it lands on AWS, what changes, and the effort.

Laravel componentAWS serviceWhat changesEffort
nginx + PHP-FPM (web)ECS on Fargate (two-container task) plus ALBDockerfile; ALB terminates TLSMedium
MySQLRDS for MySQL or Aurora MySQLDB_HOST; cutover via DMS or dump and restoreHigh (cutover)
Redis (cache, sessions, queues)ElastiCache (Redis OSS or Valkey)REDIS_HOSTLow
Horizon workersECS serviceSupervisor process becomes a serviceMedium
Scheduler (cron)EventBridge Scheduler plus a one-off ECS taskOne invocation per minuteLow
File storageAmazon S3 (Flysystem s3 driver)Move local-disk writes to S3Low to medium
.env config and secretsSSM Parameter Store and Secrets ManagerInjected as env vars by ECSLow
MailAmazon SES (or your provider)Mail settingsLow
Domain and TLSRoute 53 and ACMDNS and a free certificateLow
The "Medium" and "High" rows (containers, Horizon, the MySQL cutover) are what a migration partner usually handles.
want this run for you?
Get matched with an AWS partner who runs your Laravel migration
Get matched free with a vetted AWS partner who can file it
how a match works

How a match works (example)

  1. You tell us about the work

    You fill in a short form: what you run today, what you want to move, test or build, your stage and your region.

  2. We pick one partner

    We read your answers and pick one vetted AWS consulting partner that fits the work, the stack and the region. We reply within 24 hours; your matched partner reaches out within 5 business days.

  3. The partner checks MAP funding

    Your matched partner scopes the migration with you. Then it checks whether the move qualifies for MAP (Migration Acceleration Program) funding. MAP is for teams that are not on AWS yet.

  4. The partner files, AWS decides

    If the work qualifies, the partner files the funding request with AWS. AWS reviews it and decides. The amount depends on the workload.

  5. You pay nothing

    CloudRoute is free for startups. Partners pay CloudRoute a monthly membership plus 10% of AWS-approved funding.

AWS Activate credits are separate, and you apply for them yourself. Use Activate Founders if no investor backs you. Use Activate Portfolio with the Org ID or invite from your VC, accelerator, incubator or angel group if it is an Activate Provider. A consulting partner cannot apply for Activate on your behalf.

faq

Common questions

What is the best way to run Laravel on AWS?
For most production apps: nginx and PHP-FPM in a two-container task on ECS with Fargate behind an Application Load Balancer, MySQL on RDS or Aurora, ElastiCache for cache, sessions and queues, S3 for files, Horizon as its own ECS service, and the scheduler on EventBridge Scheduler. App Runner closed to new customers on April 30, 2026.
How do I run Horizon and the Laravel scheduler on AWS?
Run Horizon as a dedicated ECS service using the same image. Run the scheduler with one EventBridge Scheduler rule that starts a one-off ECS task every minute to call schedule:run, so scheduled jobs fire exactly once.
Does my Laravel code need to change?
Mostly no. Eloquent, migrations, jobs and Horizon are unchanged. What changes is packaging and configuration, plus any code that writes files to local disk, which must move to S3.
How much downtime is there at the MySQL cutover?
With DMS change data capture (which needs row-format binary logging on the source), a short pause to drain changes and switch settings. Without it, the time a dump and restore takes, which you should measure on a copy first.
Can AWS fund a Laravel migration?
Sometimes. MAP is filed by an AWS partner and is built for migrations with meaningful ongoing AWS spend, so a small app may not qualify. When the migration qualifies, your matched partner files it and AWS approves: typically $50K to $150K for startups. Depends on the workload; AWS approves.

Move your Laravel app to AWS with a partner who has done it before.

CloudRoute matches you with one vetted AWS partner who runs the Laravel migration: containers on ECS, RDS or Aurora MySQL, ElastiCache, Horizon, the scheduler and the cutover. The partner files MAP funding when the migration qualifies and AWS approves. CloudRoute is free for startups.

we reply within24 hours
partner-filed funding$50K to $150K
CloudRoute fee for startups$0