How I Design Scalable Laravel Architectures
The patterns I reach for when a Laravel codebase needs to survive years of growth: bounded contexts, thin controllers, and queues as a first-class citizen.
Tanjil Ahmed
Lead Software Engineer · Notionhive
Every Laravel project starts fast. The framework hands you routing, ORM, queues, and auth on day one — and that speed is exactly why so many Laravel codebases hit a wall at year two. The architecture that made the first ten features easy makes the hundredth feature dangerous. After nine years of building and rescuing Laravel systems, these are the decisions I now make before writing the first migration.
Draw boundaries before you need them
The single biggest predictor of long-term maintainability is whether the codebase has boundaries. I organize applications into modules around business capabilities — Catalog, Orders, Inventory, Billing — each owning its models, actions, and events. Laravel doesn't force this structure, which is precisely why you have to.
- Controllers stay thin: validate, delegate to an action class, return a response.
- Action classes hold business logic and are trivially testable in isolation.
- Modules communicate through events and contracts, never by reaching into each other's models.
- Shared concerns (auth, money, addresses) live in a small, deliberate core.
Queues are architecture, not an afterthought
Anything that doesn't need to happen inside the request — emails, exports, index updates, webhooks, report generation — goes to a queue from day one. This isn't just a performance decision. Designing operations as jobs forces you to make them idempotent and retryable, which is the same discipline distributed systems demand. When traffic grows, you scale workers instead of rewriting flows.
Let the database do its job
Eloquent is a wonderful tool for writing and an easy tool to misuse for reading. For dashboards, reports, and listing screens, I write deliberate queries: select only needed columns, index for actual access patterns, and reach for read-optimized query classes when a screen needs data from five modules. N+1 detection runs in CI, not in production incident reviews.
Scalability is rarely about handling ten million users. It's about handling the two hundredth feature request without fear.
None of this is exotic. Boundaries, queues, deliberate queries, and tests around business logic — that's the whole recipe. The hard part is applying it consistently when deadlines whisper that this one controller could just talk to that one model directly. It never stops at one.