Laravel vs NestJS: From "the Laravel girl" to choosing the architecture


For quite a while at We Do Dev Work, they knew me as "the Laravel girl".
It was the first backend framework I became really comfortable with, and after using it on projects such as PUT-IT-ON, where I worked on payments, scheduling, queues and other backend functionality, I understood why. Laravel makes me productive. A lot of the decisions you need to make when building a web application have already been made, the different parts of the framework work well together, and once you know the Laravel way of doing things, you can move remarkably quickly.
More recently, I've been working with NestJS, including on EngineeringScore, where we're building a backend that scans websites across security, performance, SEO, accessibility and reliability before combining those results into a transparent score. It's a very different type of project, and NestJS has made me think differently about how I structure backend applications.
The simple conclusion would be that I moved from PHP to TypeScript and discovered that I prefer one over the other, but that's not really what happened. I still like Laravel, and there are plenty of projects where I would choose it tomorrow.
What I found more interesting is that Laravel and NestJS actually belong to the same family in an important way: they are both opinionated frameworks. They don't simply give you a collection of tools and leave you to figure out how everything should fit together. Both have strong ideas about how a backend application should be built.
They just have opinions about different things.
Laravel makes many of the application decisions for me, which is a big part of why it makes me so productive. ∫ leaves more of those technology choices open, but is much more explicit about modules, dependencies and architectural boundaries, which is probably why it makes me think more about architecture.
After working with both, I've realised that this difference is much more useful when choosing between them than simply comparing PHP with TypeScript or making another list of framework features.
Being opinionated is a feature, not a limitation
Developers sometimes use "opinionated" as if it were criticism. A framework tells you how to organise something, while a less opinionated technology gives you the freedom to decide for yourself.
That freedom sounds attractive, but every decision has a cost.
If a framework doesn't tell you how to handle something, somebody on the team needs to decide. You need to choose a library, agree on a pattern, document it, make sure everyone follows it and, hopefully, make a decision that you won't regret two years later.
An opinionated framework takes some of those decisions away from you.
This is particularly useful when you're working in a team. When I open a Laravel project created by another Laravel developer, I already have a reasonable idea of what I'm going to find. Routes, controllers, models, migrations, jobs and commands have familiar places. The implementation can obviously still be good or bad, but we at least start with a shared understanding of how the application is organised.
NestJS provides something similar. If I open an unfamiliar NestJS application, I expect to see modules, controllers and providers. I expect dependencies to be injected rather than created randomly throughout the application. Again, none of this guarantees good code, but the framework provides a common language for the developers working on it.
This is why I think Laravel and NestJS are more comparable than they might initially appear. One is a PHP framework and the other sits firmly in the TypeScript and Node.js ecosystem, but both try to give development teams conventions rather than leaving them with a blank canvas.
The difference becomes interesting when you look at which decisions each framework wants to make for you.
Laravel makes a lot of decisions for you
Laravel has a very complete idea of what a web application needs.
Routing, database migrations, validation, authentication, queues, caching, events, scheduled tasks and command-line tooling all have established Laravel approaches. Eloquent gives you an ORM that feels like a natural extension of the rest of the framework, while tools such as Artisan make many repetitive development tasks straightforward.
You can replace parts of that ecosystem if you have a good reason to, but most of the time you don't need to.
That has a huge impact on productivity.
When I'm implementing a feature, I can spend more time thinking about the feature itself and less time deciding which package should solve each technical problem. There is usually a Laravel way of doing it, there is usually good documentation for it, and there is a very large community that has probably encountered a similar problem before.
PUT-IT-ON was a good example for me. The platform required a combination of functionality including payments, scheduling, queues and the normal database-heavy logic you expect from a business platform. There are plenty of architectural decisions involved in building something like that, but there are also many problems that aren't unique to the product.
I don't want to invent a new way of processing background jobs every time a project needs a queue. I don't want to design a migration system because the database schema changed. Those aren't the problems that make PUT-IT-ON unique, so having a framework that already provides strong solutions means more development time can go towards the problems that actually matter to the product.
That's what I mean when I say Laravel makes me productive.
It isn't simply that PHP is quicker to write, or that Laravel has convenient syntax. It's that the framework removes a surprising number of decisions from my day.
Productivity doesn't mean Laravel is only for simple applications
There is an obvious trap here.
When people describe Laravel as easy to use and fast for development, the next conclusion is often that it's perfect for small applications but that you need something "more architectural" once a system becomes large.
I don't think that's fair.
Laravel doesn't prevent you from creating good boundaries, separating business logic or designing a large application properly. You can introduce services, actions, domains, repositories or other patterns where they make sense. Laravel gives you plenty of room to design a sophisticated application.
The risk is actually a consequence of how productive Laravel can be.
Because it's so easy to add another controller method, extend an Eloquent model or put a little more logic into an existing class, you can keep moving quickly for quite a long time without being forced to reconsider the structure. If the development team isn't disciplined, a very productive first year can create a much less productive third year.
That's not Laravel's fault. You can create terrible architecture in any framework, including NestJS.
It does mean that developers need to recognise when the convenience that helped them move quickly at the beginning needs to be complemented by stronger architectural decisions as the application grows.
NestJS has a different opinion
NestJS felt familiar to me in some ways because it's also opinionated, but the emphasis is different.
NestJS has strong ideas about structure.
Modules define boundaries within the application. Controllers deal with incoming requests. Providers contain functionality that can be injected where it's needed. Dependency injection is part of the framework rather than something you introduce later because the codebase has become difficult to test or maintain.
That means architecture becomes visible very early in the project.
Even when you're building a relatively straightforward feature, you're encouraged to think about which module owns it, which provider should implement the logic and which dependencies that provider should have.
Sometimes that's excellent.
Sometimes it's also more work.
If I'm building a very straightforward CRUD application, there are situations where the additional structure doesn't immediately give me much value. Creating another module, provider and DTO isn't automatically good architecture simply because everything has been separated into more files.
Architecture should solve complexity, not create it.
Where NestJS started making much more sense to me was when I worked on a backend where the complexity was already real.
EngineeringScore is a very different backend
EngineeringScore scans websites and evaluates them across several areas, including security, performance, SEO, accessibility and reliability. Those results eventually need to come together to produce a score using a transparent and deterministic methodology.
From a product perspective, that's one feature: scan my website and tell me how good its engineering is.
From a backend perspective, it's a collection of quite different responsibilities.
A performance scan doesn't need to know how accessibility is measured. Security checks have different requirements from SEO checks. The component responsible for calculating a final score shouldn't need to understand every implementation detail of the scanners producing the underlying results.
There are also external services, APIs and background processes involved, which means the backend naturally has several boundaries.
In that environment, the structure NestJS encourages starts becoming very useful.
Instead of asking how we can put all of this functionality into one application, we can think about the different domains inside that application and define how they communicate. Dependency injection makes those relationships explicit, while modules give us a natural place to draw boundaries.
That's what I mean when I say NestJS makes me think more about architecture.
It's not that NestJS magically creates better architecture. A badly designed NestJS application can still have dozens of modules with unclear responsibilities and dependencies going everywhere.
The difference is that the framework keeps putting architectural questions in front of me.
With Laravel, I often feel that the framework is asking, "What do you want to build?"
With NestJS, I more often find myself asking, "Where should this belong?"
Both are useful questions.
NestJS gives you structure, but you still have choices to make
There is another important difference.
Laravel's opinions extend quite far into the technology stack. Eloquent is the obvious database choice. Laravel has its own queue system, migration system, authentication solutions and a broad ecosystem of first-party or closely integrated tools.
NestJS gives you a strong application structure but leaves more of the surrounding choices open.
You might use Prisma or TypeORM. You need to decide how persistence should work. There are different approaches to queues and background processing. Even the underlying HTTP platform isn't completely fixed.
For some teams, that flexibility is exactly what they want. For others, it's just a longer list of decisions.
Neither is automatically better.
If the technical requirements of the application are unusual, having those choices can be valuable because you're not fighting against assumptions made by the framework. If you're building something relatively conventional, having to make those decisions can simply mean spending time solving problems Laravel already solved for you.
This is probably the biggest reason I no longer think of the comparison as PHP versus TypeScript.
It's really a question of where you want the framework to make decisions and where you want your engineering team to make them.
TypeScript is still a major reason
Of course, the language isn't irrelevant.
At We Do Dev Work we use TypeScript extensively, particularly on the frontend, so NestJS has an obvious organisational advantage. Developers already familiar with TypeScript don't need to switch languages when moving between frontend and backend work, and we can use similar tooling and development practices across both.
For a full-stack TypeScript team, that's genuinely useful.
But I wouldn't choose NestJS purely because "one language everywhere" sounds cleaner on an architecture diagram.
A team of experienced Laravel developers isn't suddenly going to become more productive because management decided TypeScript is more modern. Existing expertise matters, and so does the ecosystem surrounding an existing application.
The technology choice has to include the people who are going to use it.
That's particularly important for an agency, because we're not choosing our favourite framework once and then using it forever. Different clients have different existing systems, different internal teams, different requirements and different plans for who will maintain the software after launch.
Sometimes Laravel is the obvious choice. Sometimes NestJS is. Sometimes neither is.
So when would I choose Laravel?
After working with both frameworks, I would lean towards Laravel when the application benefits more from its integrated ecosystem than from having every architectural choice exposed.
Typical examples would include:
A business application with significant CRUD and database functionality.
A platform that needs authentication, queues, scheduled jobs, notifications and similar common backend functionality.
A project where getting a solid first production version online quickly is particularly important.
An application being built or maintained by a team with strong PHP and Laravel experience.
A project where Laravel's existing conventions already solve most of the technical problems surrounding the actual business logic.
This is why Laravel worked so naturally for something like PUT-IT-ON. There was plenty of custom business logic to build, but there were also many conventional web application problems where I didn't need the freedom to invent my own solution.
I needed them to work.
Laravel let me focus on that.
And when would I choose NestJS?
I'd lean towards NestJS when the structure of the backend itself is a significant part of the engineering challenge.
For example:
An application with several clearly separated domains.
A backend coordinating multiple external APIs or services.
Systems with several workers or processes performing different responsibilities.
A TypeScript-heavy development team where frontend and backend knowledge frequently overlaps.
Applications where explicit dependency boundaries will become increasingly important as the product grows.
Projects where we deliberately want more control over persistence, infrastructure or other parts of the backend stack.
EngineeringScore fits much more naturally into that category. The scanning domains, scoring logic and supporting services give us real boundaries to model, so the architectural structure isn't there because NestJS told us to create it. It's there because the product actually has that complexity.
That's an important distinction.
What I ask before choosing now
A few years ago, I probably would have chosen Laravel simply because I knew it best. That's not necessarily a terrible reason, by the way. Being productive with a technology you understand is often more valuable than choosing the theoretically perfect framework you've never used in production.
Today I'd make the decision more deliberately.
Before choosing between Laravel and NestJS, these are the questions I'd want to answer:
What kind of application are we actually building?
How much of the backend is conventional web application functionality?
Where is the real complexity in the product?
Does that complexity naturally divide into separate domains?
How many external systems and APIs will the backend coordinate?
How quickly do we need to reach a useful production version?
Which technology does the existing team know best?
Will developers regularly work across both frontend and backend?
Do we benefit from choosing our own infrastructure components, or are we just creating decisions we don't need?
Who will maintain this application after two or three years of development?
That final question is one I've started appreciating more as I work on larger projects.
A framework choice isn't only about how pleasant the first sprint feels. You're choosing the conventions that future developers will encounter when they open the project after hundreds of features, integrations, fixes and changes have accumulated.
The best framework is therefore not necessarily the one that lets you write the first endpoint fastest, nor is it automatically the one that gives you the most architectural tools.
It's the one whose opinions fit the application you're actually building.
Am I still the Laravel girl?
Probably.
I still enjoy working with Laravel, and there are many projects where its productivity and integrated ecosystem would make it my first choice. Working with NestJS hasn't convinced me that Laravel was the wrong framework; it has simply given me another way of thinking about backend development.
My original feeling about the two frameworks hasn't really changed either: Laravel makes me productive, while NestJS makes me think more about architecture.
What has changed is that I understand better why.
Laravel is opinionated about a large part of the application stack and removes many decisions that I simply don't need to make on every project. NestJS is opinionated about structure and makes modules, responsibilities and dependencies much more explicit, while leaving more of the surrounding technology in our hands.
That's why I think they belong in the same conversation despite coming from completely different ecosystems. Both frameworks are trying to help developers deal with the complexity of building and maintaining backend applications; they simply choose to remove different kinds of complexity.
And after working with both, that's the question I'd now ask before choosing between them: which decisions do I want the framework to make for me, and which ones are important enough that I want to make them myself?
Related articles

How we take total control of our operations at WDDW
As WDDW grew, so did our SaaS costs. Here's why we built our own internal tools, and how they improved efficiency, reduced costs, and gave us full control.


The cost is not zero
AI makes software development faster, but not free. Learn why engineering, architecture, QA, and experienced developers remain essential in the AI era.


SEO for developers
Where marketing and code finally meet If you’ve ever built a website and heard someone say, “We’ll handle the SEO later,” you already know how that ends. Later never really comes. SEO isn’t a last-minute checklist after launch. It starts in your code, in how your pages are structured, and in how your data is served to both humans and search engines.

Ready to take your business to the next level.
Partner with a professional team that turn ideas into powerful business experiences and scales with your growth.
