Scalable architecture patterns for modern web applications
An overview of scalable patterns — monoliths, microservices, serverless, event-driven — plus database scaling, queues, and load balancing.

As an app grows, the architecture that was fine at 100 users starts to crack at 100,000. Scalability is about designing systems that handle more load without a rewrite. This article surveys the patterns and the trade-offs behind each.
1. Monolith vs microservices
- **Monolith** — one deployable unit. Simple, fast to start, but couples everything.
- **Microservices** — independent services. Scale and deploy separately, but add network and ops complexity.
Most successful apps start as a well-structured monolith and split only the parts that need independent scaling.
2. Serverless
Run code without managing servers (AWS Lambda, Cloudflare Workers). Great for spiky, event-driven workloads.
- **Pros**: scales to zero, pays per use, no infra.
- **Cons**: cold starts, vendor limits, harder local debugging.
3. Event-driven architecture
Components communicate via events instead of direct calls. A user action emits an event; other services react.
txt
order.created -> [email service] [inventory service] [analytics]
Use a broker (Kafka, RabbitMQ) so producers and consumers stay decoupled.
4. Scaling the database
The database is usually the bottleneck. Options:
- **Read replicas** — send reads to replicas, writes to primary.
- **Sharding** — split data by key across nodes.
- **Caching** — Redis in front of hot queries (see caching guide).
- **Indexing** — the cheapest win for slow queries.
5. Load balancing and statelessness
Put a load balancer in front and keep app servers stateless so any instance can serve any request. Store sessions in Redis or signed cookies, not server memory.
6. Queues for resilience
Push slow work (emails, image processing) onto a queue so requests return fast:
ts
await queue.publish("send-welcome-email", { userId });
// handled asynchronously by a worker
This smooths traffic spikes and prevents one slow task from blocking users.
7. Choosing a pattern
| If you need... | Consider |
|---|---|
| Fast start, small team | Monolith |
| Independent scaling per domain | Microservices |
| Spiky, unpredictable load | Serverless |
| Loose coupling, async work | Event-driven + queue |
| High read throughput | Read replicas + cache |
Takeaway
Scalability is less about a single "right" pattern and more about removing bottlenecks: stateless app servers, cached reads, decoupled work, and a database that can keep up. Start simple, measure, and split only where the data tells you to.