It's been a while since I've last used node to build a backend, and the last time I did Express was the go-to solution. Is that still the case?
I don't have much time to do too much research and I usually default to the most popular solution in such cases.
Maybe it's still standard, but if you don't want to shoot yourself in the foot, just stay away from it.
Express's API is horrible. It's not integrated with Promises (async/await) at all, so be prepared to wrap every async endpoint (so probably all of them) with a custom error handling wrapper. If you don't (and don't have a big catch-block around the whole implementation), an unhandled error will hang the connection forever without a response.
Also, the API makes it pretty much impossible to write "wrapping" middleware, for example if you want output validation. As soon as an express middleware calls `next`, it's done and there's no way intercepting it before a response is sent.
It also still doesn't support Node's HTTP2, just some (nowadays) weird third-party HTTP2 implementation.
The standard `compression` middleware also seems abandoned, not supporting brotli (so you'll have worse loading times), despite Node.js natively providing the required functions for years.
The thing is, express's foot guns are well known and well documented, and you basically just enumerated them. If you pick another framework then you'll be left exploring its footguns on your own. That may or may not be worth it to you, but it's not obvious to me that choosing the well-known framework is a worse choice than choosing the ones that try to solve its problems but don't yet have the rough edges discovered and documented.
I think there's a slight difference between doing something that nobody's ever done before and just choosing a less travelled path. In any case, I'd rather not use the tool with well-known foot-guns, hoping that all developers in the project (and future ones!) do know these foot-guns as well.
I'd rather chose a tool with less foot-guns (or if not possible: provide easy workarounds that are consistenly used). With the design-flaws of express (no fault to it, since it predates standardised Promises by more than 5 years) and the availability of a simple and sane evolution of its API (koa), I really don't get why so many still cling to express.
I consider Koa to be a sensible evolution of express (even by the some of the authors).
Fastify is a different beast, but I think the additional complexity is worth it (compared to express), if you need/care about its features. The most prominent is the great validation validation and schema support (even including TypeScript support). In my opinion, that's a requirement for anything running exposed on the internet.
For a tiny toy project, I'd rather use koa or a plain Node.js http.Server. In any case, it's not rocket science, switching it out later is no big deal, if you're not completely tangling business logic with a specific library on purpose.
Not only is expressjs de-facto, it actually is a community design from before Node.js existed, with earlier implementations (connect, jackjs), including on non-Node.js SSJS-platforms; cf. [1]. Moreover, an expressjs/JSGI middleware can plug-in and directly run off the Node.js core http API, without the additional expressjs routing, etc.
Nothing really, it completed its mission of a portable environment across SSJS, and saw quite some implementation effort. The commonjs module loading convention (but not necessarily the particular core modules such as for fs, http, etc.) became a standard for bundling in browsers even, before ECMA standardized ES modules, and their dynamic nature make them being used on Node.js until today, such as for expressjs. But around 2010, Node.js became the leading, then the only relevant SSJS platform.
Fastify is absolutely fantastic. It has the concept of "type providers", allowing you to pair it with fastify-type-provider-json-schema-to-ts (for JSON schemas) or another typing system of choice, such as Zod, to obtain strongly typed queries, request bodies, and responses in handlers with TS types derived on the fly at compile time. It also validates data returned from handlers to conform to schemas, reducing the likelihood of accidentally leaking sensitive information. And it's faster than Express, even with validation.
Fastify has a nice modular architecture, decent popularity, growth trending upwards (so more future proof), first-class support of async and typescript (it's not cobbled on like it is with express).
Conversion was mostly easy because most web frameworks are pretty similar. It's less an issue of an individual frameworks features and more how popular it is. For example, a lot of people use passport for auth, so using a popular solution is more likely to have a well-supported plugin for passport, which makes conversion trivial.
On a practical note, I did have some minor roadbumps with the typical PITA issues like dealing with file-streams and multipart.
We like fastify for structure, types, perf, and maintainer responsiveness. I can count how many bugs we have had.
The backwards incompatibility is frustrating as most of the major changes could have been done in non-breaking ways. That makes it harder to recommend for people who do software for work - it is par for the course of the economic waste that is the JS framework upgrade treadmill, which may seem normal, but isn't.
I'd still generally recommend something like Django (!) or, if you need to go thin, fastAPI, as more complete, stable, & open governance than many node frameworks. Frustrating as V8 is an amazing engine.
I've tried building production apps on top of server frameworks that are constantly innovating, and it's a massive PITA. You can't not update because there are security fixes that you need, but the API surface is constantly changing to support the new great thing.
I think it's a good sign that the most popular server framework for JavaScript has finally stabilized and isn't innovating any more. We might finally be at the point where we can just build an app without constantly chasing the new.
I love threads like this, it's so stereotypical JS. OP asks if it's the de-facto choice which it objectively is, but everyone recommends their pet project or favourite library instead.
FWIW I was planning to respond “yes, it is the de facto solution, even if I wish it weren’t” and probably leave it at that. Granted I don’t have my pet project to recommend (I left it behind with previous employer), and maybe I would if I had it to recommend. But I’d still acknowledge first that express is the de facto solution.
Also FWIW, there are a bunch of other popular options… but nearly all of them have roughly the same interface and follow the same general principles as express. Again, I wish it weren’t so. But you’re right, that isn’t responsive to the question being asked.
To be fair for me the first 10 root comments almost all recommend Express or Fastly, no obscure pet projects or anything. So there does seem to be a pretty clear consensus.
I wouldn't consider Meteor a "backend" tool, but it is still great for a quick start and rapid development. If you're just establishing your project and there's no strong development expertise and culture in your company, Meteor will suit you quite well as it removes the hurdle of making a ton of decisions that will affect your productivity.
Meteor is fullstack, so you can reuse code on the front- and backend, which is nice for validation and business logic.
In the last ten years I worked for more than a dozen startups that based their business successfully on Meteor. Some of them got big and none has regretted it.
I have worked with Nuxt.js, Sapper (now Sveltekit), Play Framework an many more; all great, but for many projects I would still consider Meteor the strongest contender.
I did the same research a few months ago. There are a lot of really cool alternatives which is fun and exciting, but at the end of the day I went with express. It's super stable, huge community, endless online tutorials and content.
The most tempting alternatives were hono and fastify. Hono felt not mature enough.
At the end of the day your server framework is very rarely the bottleneck in your system's performance, so it matters less.
indeed. I hate projects that make changes for no reason. If it does everything its supposed to do and does it well, it's just done. Go work on something else.
Yes it is, Bun is promising but still in early stage. If you're looking for a battle-tested framework I would suggest Nest.js, which supports both Express and Fastify in a virtually transparent way.
Has it been abandoned or is it just done? It's still sitting at 29 million downloads a week, so while it doesn't get frequent updates I wouldn't call it abandoned unless there are major security flaws that are being left unaddressed.
Not every package needs to have multiple updates in a year.
Who knows. They were working on http2 6-7 years ago and it hasn't arrived. I was under the impression the primary dev stopped working on it and some people were able to get maintainer access for security updates but that's about it. Maybe some people re-started development but not sure and Fastify has an express compatibility layer so it's not compelling to me.
2023 I'm only thinking about express if a legacy app using it falls in my lap.
I'd definitely suggest at least considering Nest.JS.
There's totally nothing wrong with Express (or Koa or Fastify) projects, but Express based projects tend to share problems with all others based on minimalistic-based frameworks - no skeleton means tons of discussions about favorite ORM, Logger, Validation, whole story about service vs helpers etc.
If I can skip it, I always do. Decision paralysis can be a killer.
It seems like it. There are alternatives like Koa and Fastify, but none of seem to strike quite the balance that express does. I pray that one day express 5 will get released and they’ll finally fix the whole async middleware not handling errors properly thing though. That’s gotta be one of the most annoying quirks that has just been quietly sitting there untouched for years at this point. Maybe one day.
I guess there’s Bun and Elysia now too, but that’s pretty bleeding edge by comparison.
Anytime an error happens inside an async middleware in express, you have to explicitly catch it and pass it directly to the `next` function, otherwise it'll just disappear and any kind of error logging middleware you have later on will never see it. In synchronous functions any error is passed automatically. You can write more middleware to address this, or just manually catch everything, but it just means more boilerplate. There's no reason to expect different types of middleware to have different behaviour unless you already know. It's not catastrophic, but I expect more consistent design from such an established library, especially considering how long this has been an issue.
If you're sure you want a traditional strictly-serverside backend, Fastify is like an improved Express. But your project's success might depend on going beyond a hasty sanity-check that presupposes app architecture. What's your front-end look like? For React, using a framework like Remix (or Next.js) that spans client and server runtimes, could make Fastify/Express potentially moot.
I'd say adonis is the best now as you can iterate to a full product very quickly.
It's full stack but still amazingly fast (comparable to fastify). You can choose what you need in order to improve speed too. The syntax mimics Laravel which is the easiest to use, most complete full stack framework of any language.
Obviously, somewhat opinionated claims and my main job isn't programming so take it for what it's worth.
Even being used to it (from other languages), it's super jarring in JavaScript because it's redundant. JS has other, better ways to achieve the same result, so it's generally a step down just to be more familiar for non js devs
I’m teaching a highschool kid web development and it would be very nice to be able to teach the same standard on the back end as we use on the front end.
I think Deno could be a good choice for that—it's an entire server side JavaScript runtime built around the idea of using web standards instead of server-specific code.
In addition to using standard Request and Response objects in its built-in server framework, Deno's approach to dependencies and TypeScript lends itself really well to educational settings—with no compilation step and no package management step, it's as simple to get started with Deno server-side as it is to start with HTML/JS in the browser—just open up a text editor and start writing!
I think high school is too early to be thinking too hard about what is used in industry.
I learned to program with Macromedia Flash, which was big at the time but was completely irrelevant by the time I actually was ready for my career. I don't regret it at all, though—it was perfect for me learning at the time, and taught me the skills that I've used to pick up dozens of different technologies since then.
For education it's far more important to choose technologies that minimize the barrier to entry and allow someone to start learning meaningful skills quickly, rather than forcing them to slog through the instruction manual for an industrial-strength technology before they even understand the basics. We don't apologize for starting a beginner woodworker on a lathe rather than a CNC machine.
I feel like it's a matter of the beast you know vs working with something new. A lot of packages of been created to work with express so when working with it you get a larger ecosystem available to you. However, I think it's akin to React for frontend where just because it's the standard for node these days doesn't mean it should be
I've been on various projects that utilized Express, Koa, and NestJS (which wraps Express or Fastify).
Of the three, I'd choose Koa again over the others. Their design works better with modern javascript (async/await). While there may be fewer middleware packages for Koa than Express, it's usually not that hard to write your own if you can't find what you need.
For NestJS I didn't care for the decorator-driven "Spring-like" design. In JS codebases it's more natural to take a functional approach.
Nitro is the server baked into nuxt 3. I feel like web server frameworks have all been circling around the same set of features for like 10 years though.
It's 2023 and there is a web framework that "can't" handle websocket at all. (Not even just proxying and doing nothing else.) Feels like a joke to me. (Yep, this issue hit me hard when I am writing a chat application, waste me 3 days to find out why it didn't work during development but in production)
I tried Nitro soon after Nuxt 3 came out and was very unimpressed. The whole thing felt half-baked, with missing features and essentially zero documentation.
Express is still the "go-to" now, because it's the rare case of a Node library that's stable, battle-tested, and doesn't change much. (Yes, the maintainers having not been able to release v5 has actually been a sort of advantage.)
But, there are other great options to go with now, and you probably won't go wrong with fastify or hapi.
I've never used Hapi, but I followed the process when Walmart wanted to discontinue the project. Unfortunately, even though it's quite an interesting backend framework, I don't see the need to use it with the existence of other solutions.
I just use the native Node APIs and write the tools I need when I need such tools. The really tough problems I would need something like Express to solve for are not solved by something like Express.
All of the responses talk about a framework and I know you're thinking you need one too. But, I'm more curious about your plans to host things.
The reason I ask is because there are alternatives, like Google Cloud Functions [0], where you don't need a framework at all. You just write a handler and you're done. Connect it with Github actions for deployment.
There are other services out there, but I like GCF cause it'll auto scale. Need a database? Cloud SQL Postgres. Need a queue... Cloud Tasks... etc... so many problems solved in a relatively non-vendor lockin way.
EDIT: I'm getting downvoted for trying to make a helpful comment to the OP. Good work HN!
Last I checked, Express is extremely slow and will significantly impact your SEO if you're a content business and doesn't really scale very well if you get huge amounts of traffic like I have.
These days I use Go, Deno or Crystal which is much faster.
For hosting I recommend Cloudflare Pages, Vercel, (maybe Netlify) and Render.
The frontend impacts your SEO way more than your backend, especially if you're using a typical framework. Additionally, things like your database (more specifically, your schema and your queries) will impact the speed of your backend more than any particular library.
Express's API is horrible. It's not integrated with Promises (async/await) at all, so be prepared to wrap every async endpoint (so probably all of them) with a custom error handling wrapper. If you don't (and don't have a big catch-block around the whole implementation), an unhandled error will hang the connection forever without a response.
Also, the API makes it pretty much impossible to write "wrapping" middleware, for example if you want output validation. As soon as an express middleware calls `next`, it's done and there's no way intercepting it before a response is sent.
It also still doesn't support Node's HTTP2, just some (nowadays) weird third-party HTTP2 implementation.
The standard `compression` middleware also seems abandoned, not supporting brotli (so you'll have worse loading times), despite Node.js natively providing the required functions for years.
I'll second `fastifiy` or `koa`.