I have deployed Laravel to AWS for startups doing a few hundred users a day and platforms handling millions of requests. The architecture below is the shape I keep coming back to, because every piece scales independently and nothing is exotic.
The core architecture
- Application Load Balancer terminating TLS and health-checking instances
- EC2 instances (or ECS Fargate containers) running PHP-FPM + Nginx in an Auto Scaling Group
- RDS MySQL or PostgreSQL with Multi-AZ for failover
- ElastiCache Redis for cache, sessions, and queues
- S3 for user uploads, served through CloudFront
- A small dedicated worker instance (or ECS service) for queue workers and the scheduler
Make the app stateless first
Before anything scales horizontally, the application must hold no local state: sessions in Redis, files in S3 via the s3 filesystem driver, and cache in Redis. Once that is true, adding or removing instances is a non-event, and deploys stop being scary.
Separate web and worker workloads
Queue workers and cron (the Laravel scheduler) should not run on web instances. Auto-scaling kills instances; a terminated worker mid-job is a corrupted import. A small dedicated worker tier with Supervisor keeps background processing predictable, and you can scale it on queue depth instead of web traffic.
Deploys without downtime
My pipeline builds a release artifact (composer install, npm build, config:cache), ships it, runs migrations with --force, and switches a symlink — or, on ECS, rolls a new task definition. Either way the rollback story is 'point back at the previous release', which has saved me more times than I can count.
Cost notes from real projects
Most teams over-provision EC2 and under-provision RDS. Start with smaller app instances behind the ALB (they scale out), put the budget into the database, and turn on RDS Performance Insights — it is the best money-saver AWS gives you for free.

