This article explains how we chose our NodeJS framework at Theodo, the company I am working for. Among others, we focused on ExpressJS, KoaJS, NestJS, MeteorJS, and SailJS.
At Theodo, we have been working for a long time with API Platform and Django and they provide for everything we need.
Recently, more and more clients have been wanting to use NodeJS, which lead us to choose a NodeJS framework. However, there are so many such frameworks that we didn’t know where to start. Furthermore, choosing a new framework is a crucial decision to make for a company, that engages it for at least a couple of years.
So we started looking for a NodeJS Framework that would empower us to write code that would be:
- 🔒 Secure: No need to say how much security is important, I intendedly placed it first 🙂 Both the company operating the website and the end users should be protected.
- 🚀 Scalable: I am not so much talking here about scalability in terms of traffic, but rather that developing a feature on the very first day of the project or after 2 years of active development should be just as straight-forward.
- ♻️ Maintainable: Zero bugs! And near-to-impossible to introduce one.
I will now go more deeply into our decision process.
Select front runners
We didn’t have the time nor the will to benchmark every single NodeJS framework out there, so we first decided to select 4-5 front-runners. For this, we picked the following:
- More than 10k 🌟 on Github
- Last bug fix less than 1 month old, last feature less than 3 months old
- Answer to issues in less than a day
- At least one major sponsor backing the NodeJS framework
Determine decision criteria
One common pitfall is to consider right away the pros and cons of each solution. This leads to highly opiniated discussions, that can drift from the initial objective.
Take this statement for example: “NestJS is cool because it makes use of AngularJS CLI”. We don’t know if it is a good thing in regards to our target, and we cannot evaluate how other NodeJS frameworks compare.
This is why we first determined what would be our decision criteria.
|🔒 Security||Is there a security module available out of the box?|
|Does it handle access control by routes, roles, input validation?|
|🚀 Scalable||Is the developper guided in all of his architectural choices? Via injection dependency for example, configuration files, etc.||The learning curve should be pretty smooth, and it should be near-to-impossible for a developper to do something the wrong way.|
|Is the documentation exhaustive, with code snippets?|
|Is there an available ORM ? Are there migrations? Is there normalization/serialization? How comprehensive is entities relationship?||We mostly use SQL databases (PostgreSQL) for the use cases we meet, so the thoroughness of the ORM is important to us.|
|♻️ Maintainable||Is the framework typed?||Since we have started using TypeScript, the developper experience has improved a lot: prevent bug, auto-imports, jump to definitions, etc. A natively typed framework is a plus.|
|Is the framework himself tested?||How easy is it to do unit testing, integration testing?|
|Are there developpment / debug tools?||We found out this depends more on the IDE than on the NodeJS Framework. VScode, for example, has amazing built-in debugging support.|
|Are there a lot of “magical methods”, indirection? Are such behaviours easily overridable if needed?||It might be great when prototyping a website, but when you want to have a robust production, not understanding what happens under the hood is a major drawback.|
|Is the framework decoupled from the ORM, the client?||Some project start from scratch, others have a legacy. Sometimes we migrate part of an application. For these reasons we want all frameworks/librairies of our stack to be loosely coupled.|
|👪 Support||Is it widely adopted by the community? What is the trend like? How many 3rd party modules are there?|| Tools such as google trends can be useful here:
Github also provides a lot of interesting insights.
|How is the support for issues? Are there experts close by, in Paris? France?||Our office is in Paris 🙂|
|Are Theodo developpers enthusiastic about this framework?||It may sound trivial, but you cannot choose a framework if nobody in your company is willing to promote / work with it.|
These criteria are of course very opiniated. You’ll notice for example that I didn’t mention performance at all. This is because the number of rps (request per second) a framework can handle has never been a blocking factor on any of our projects so far. Using Varnish cache or a CDN among other solutions has always proven itself to be enough.
On the other hand, you can dispatch some criterion, like the ORM if you don’t work with SQL databases.
We then gave a note to each criterion, ranging between 0 and 3:
- oo : No support
- oo : Partial support
- oo : Extensive support
- oo : The best available
And here are the scores :
|Criteria||MeteorJS||NestJS||SailJS||KoaJS + middlewares||ExpressJS + middlewares|
|🚀 Architectural guidance|
|♻️ Debug tools|
|👪 Internal Enthusiasm|
The decision: which NodeJS framework we chose
MeteorJS was KO’d, because of the drawbacks that are inherent to its good qualities. Its all-in-one philosophy makes it possible to protoype an app very quickly. However our clients often already have an existing frontend or infrastructure, so Meteor was not what we were looking for.
ExpressJS and KoaJS
These 2 frameworks are very similar. We didn’t select them mainly because they provide too much freedom when designing the architecture and choosing the middlewares. Plus some of these middlewares seem to have less support and poorer documentation.
And the winner is…
We see on our benchmark that it scores more on most criteria than the last remaining contender SailJS. We were especially receptive to all the good design patterns and architectural stability it promotes, which makes it closer to Symfony or Django that we know quite well.
It relies on ExpressJS under the hood, so it basically includes all its features and is compatible with most of its middlewares. But it can be substituted with another library, in particular there is built-in support for Fastify if performance is a concern to you.
The fact that it is typed with Typescript has a lot of amazing consequences: enable database migrations and object validation based solely on the entity interface, ease code understanding, improve the developper experience, etc. This, as well as great integration with third-party librairies like Passport and Typeorm are the main raison NestJS scored high for many different criteria.
Its surging popularity is also spectacular, and the v6 release went live a few weeks ago with a bunch of amazing features.
Again, I can’t emphasize too much the fact that NestJS proved to be the best solution for us, but that doesn’t mean it is for you!
The nest step (next step, get it?) is to get better at NestJS. Indeed, working on the right framework is not enough if your teams can’t make the most of it! This is why we launched the NestJS Paris Meetup, to share with other aficionado insights and good practices about this framework. The CFP for the next event in Paris in May is opened (here) by the way 😉
I’d love to get your thoughts on this! How did you choose your NodeJS framework, what were your decision criteria?
You liked this article? You'd probably be a good match for our ever-growing tech team at Theodo.