I have been confused recently with the moving best practices. What is the server architecture Next.js is most often plugged into?
I have been confused recently with the moving best practices. What is the server architecture Next.js is most often plugged into?
expressjs at this point is battle-tested, minimal, easy to understand (both in usage and internals) and have a huge community still. It's very mature and does what it does well.
I thought this was slightly awkward due to error handling, but it looks like Express 5 (in beta) supports async callbacks natively.
Since iirc you send responses directly from handlers in Express, I'm not sure the latter is possible even with express-promise-router since you basically need downstream routes/middleware to return a Response object rather than send it directly.
I think Express is never going to unify with Koa's direction since it's just too disruptive to Express' ecosystem (the v5.x branch is stale) which is probably for the best.
const db = {
async getUsers() {
throw new Error("failed to connect to database");
},
};
app.get("/", async (req, res) => {
const result = await db.getUsers();
return result;
});
There are various monkey patches/wrappers you can use to make async errors work the same as sync errors, but it is easy to forget and hard to understand, especially for newbies. Many other frameworks handle async/sync errors in a more consistent way.> Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error. For example:
> app.get('/user/:id', async (req, res, next) => { const user = await getUserById(req.params.id); res.send(user) })
> If getUserById throws an error or rejects, next will be called with either the thrown error or the rejected value. If no rejected value is provided, next will be called with a default Error object provided by the Express router.
There hasn't been a new beta in a long time. Last release about a year ago and then the 1 before that about 3 years ago. Not a very convincing beta.
The maintainer said this three months ago in a comment on that issue:
> Express 5 is pretty much completed at this point, and we're just finishing up the last code merges in upstream modules in order to bump the dependencies finally in the 5.0 branch.
Like how Windows XP on an old computer still "works just fine"?
What does work just fine in terms of software that's ever updating mean? It doesn't matter if it's called 4 or 5 or any other label.
On the comments: my point is more that we should not base the NodeJs standard on something that's not regularly maintained / updated. There are infinite amount of things that can be improved on for a "standard" server framework used by millions. You don't say Node "is done" and leave it? People would definitely fork it or move on (as happened in the past).
Is it? It performs slower than e.g. Fastify. Don't see how that's doing well.
> Who cares how old something is, if it works well, why not use it?
It doesn't. That's the whole point. Software is always evolving and I doubt it's even close to complete. There hasn't been meaningful updates to Express in a long time. Why do people use it and/or promote it as a standard?
It's such a marginal difference when you consider real-life applications built with either express or Fastify though. Seldom is the actual bottleneck which HTTP library you use (unless you're at a really, really, really big scale), and more about how you structure your code, database and general architecture. I can count on one hand the number of times I've had to care deeply about the HTTP stack in order to optimize something, while I've probably had to optimize 100s of web products over the years, all done without touching the HTTP parts at all.
> It doesn't. That's the whole point. Software is always evolving and I doubt it's even close to complete. There hasn't been meaningful updates to Express in a long time. Why do people use it and/or promote it as a standard?
How to handle HTTP requests kind of doesn't. HTTP 1.1 continues to work, and will continue to be sufficient for at least 90% of all the use cases on the web for a long time.
I know that the JS community generally suffers from "If it hasn't been updated in the last year, it's probably broken and not modern enough" syndrome, but some software actually end up being "finished" and good enough for the task at hand. What improvements could you actually add to express without breaking the API interface that millions of applications depend on? Sometimes stability is wanted and needed, and that's how you get mature software. Who wants to rewrite their application and architecture every time some library you happen to use decides to "improve" it?
If you take out your 386 and boot up Dos 3.1 it'll; continue to work too. Let's just not improve, right?
> but some software actually end up being "finished" and good enough for the task at hand
Like dead? Do you ever stop learning and growing? Are you "finished" too? There are new vulnerabilities, new compatibilities, existing bugs, different use cases, etc - you think it's finished = turning a blind eye.
> It's such a marginal difference when you consider real-life applications built with either express or Fastify though.
That's how we get Electron and everything become a resource hog. Oh it doesn't matter. Oh marginal difference. No don't recycle, don't do good for the environment and anything in life because it's all marginal. Why even reply? It's a marginal difference.
No, we can do better and will.
Because for the most part - it doesn't need them.
Can you build a better express? Maybe. Lots of folks are trying that still, and you're welcome to use the tooling they put out.
Is express dead? Hell no.
Express is well documented, well supported, getting security patches, and comes up entirely clean for a new install (including most of the optional packages you might add).
Express has some sharp edges (it's been mentioned plenty above, but mainly because the framework predates the wide adoption of native promises in the JS space), but again, they're well known and relatively straight forward to work around.
---
Long story short, this:
> It doesn't. That's the whole point. Software is always evolving and I doubt it's even close to complete. There hasn't been meaningful updates to Express in a long time. Why do people use it and/or promote it as a standard?
Is an ignorant take. People promote it because it's a good tool.
Next you'll be telling me that I shouldn't use Bash because Bash 5.0 came out in 2018 and only got two minor point releases over the next 5 years. But that sounds dumb, huh?
What's dumb is not being able to tell the difference. It's not about the numbers.
https://git.savannah.gnu.org/cgit/bash.git/ shows there are constant updates. Things are being worked on. Your example proves my whole point. There are updates every year for many years.
Express? Not so. There are many gaps in its history. And for a tool like Express that has way more surface area it is in need of a lot more testing and updating e.g. if NodeJs changes something it breaks.
Does Bash need to make sure it works with HTTP3, Brotli or many other things that came out? No.
> Because for the most part - it doesn't need them.
Right, let's go back to the Stone Age. You don't need clothes either - just a leaf. You're just so dismissive on innovation then why bother? You don't even need NodeJs. Back to assembly and punch cards...
> Is an ignorant take.
Yes, yours. As shown above by your example.
> People promote it because it's a good tool.
And how do you know that? Where are the stats? Or people just google for NodeJs server, see the top response being Express and just do that. The cycle then repeats. Have people promoting it actually benchmarked, compared and investigated all the tools before making this informed decision? I'm sure you've heard from each and everyone 1 of them to know the answer eh.
Imo the docs need a major re-write, beginning at "getting started". New users don't know whether they should use "fastify-cli gen", "npm init fastify" or copy manually from the "getting started"-guide.
And people also tried to push their fastify-plugins to the top of the plugins-site by adding a "@username" for every plugin: https://i.imgur.com/hHyI6JO.png (left are the old docs, right are the current docs where ppl try to game the system).
Also, fastify-cli needs to rework the custom options in typescript projects imo.
Ok, that's all. Other than that, fastify rocks!
One thing nice about Koa is that it's simple, so it's timeless in that way—it's not a moving target nor does it try to do something that needs a lot of core maintainers.
They recently pushed their long awaited v5 update, which adds a Koa transport alongside the historic express transport, and improves the "code reuse between client & server" story for schemas/models/types.
I really like express + routing-controllers [1], if you're on typescript.
Express was really cool and different from what was out there at the time (at least in terms of simplicity and JS support).
But nowadays there's not a lot of difference between them. Sure, some are more ergonomic than others in certain areas but the patterns are almost the same in all of them.
The only exception is when I’m working inside an established Node shop where they already have a prolific framework, I’ll reach for what they already have in that case to avoid fragmenting their stack. Almost always, that’s express.
fastify is performant, thoughtfully designed, and well architected.
So I'd still say Express is the main choice. Personally I've never loved the Express API as it encourages a lot of heavy mutation (Koa does too), so I tend to be on the lookout for good alternatives - I haven't seen any that seem to be sticking (gaining significant enough community to bet on) more than Express.
There's a few things like Next/SvelteKit that cover all bases in one, from your web app backend -> SSR frontend -> client states, but if you're looking at pure backend for e.g. an API, Express is still going strong.
- With a bunch of middleware included and pre-configured, like body-parser, cookies, Helmet, etc. All express middleware works with Server.js
- async/await routers as expected: get('/users', async (ctx) => {...}); (ctx inspired by Koa)
- Websockets, where messages behave just as another route: socket('message', async ctx => { ... });
fastify https://www.fastify.io/
nest.js https://nestjs.com/
hapi.dev https://hapi.dev/
All are better than express.js. It is annoying that express is still go to for many where its ecosystem is pretty dead.You write your own middleware stack, and router every time you start a new "typescript" server project?
Of course not. If you're not using a third party library you're using your own framework. The Node.js API is too barebone for any serious web application.
That is still framework nonsense. If I wanted framework nonsense I would just use a framework.
Architect serverless (https://arc.codes) is pretty good for serverless.