Hacker News new | ask | show | jobs
by dminik 458 days ago
Tbh the entire middleware system in Next is awful and everyone would be better off if it was scrapped and reimplemented from scratch.

For starters, there's no official way to chain multiple middlewares. If you want to do multiple things, you either stuff it all into a single function or you have to implement the chaining logic yourself. Worse, the main functions (next, redirect, rewrite, ...) are static members on an imported object. This means that if you use third party middlewares, they will just automatically do the wrong thing and break your chaining functionality.

Then, there's no good way to communicate between the middleware and the route handlers. Funnily enough the only working one was to stuff data through headers and then retrieve it through headers(). If someone knows your internal header names this could be very unsafe.

One additional issue with that is that headers() turns your route handler into a dynamic one. This opts you out of automatic caching. I think they recently gave up on this entirely, but this was the second biggest feature of Next 14 and you lost it because you needed data from the middleware ...

And lastly it still hides information from you. For whatever reason request.hostname is always localhost. Along with some other properties that you might need being obfuscated. If you really wanted to get the actual hostname you needed to grab it out of the "Host" header.

I'm not really surprised that the header/middleware system is insecure.

5 comments

This is my biggest complaint about nextjs. The middleware implementation is horrific.

No way to communicate information from middleware to requests means people encode JSON objects into text and add it as a header to be accessed from requests using headers(). They put session/auth info in there.

I would never recommend the framework to anyone on this basis alone.

They actually appear to be working on "Interceptors" which is what you're describing; https://github.com/vercel/next.js/pull/70961
Wait, are you seriously saying the mechanism that has existed in Express for years is broken in Next.js?

What a joke.

I would argue if you're trying to chain middleware or communicate between middleware, you're already holding it wrong. In basically every other framework you would have similar issues, in that there is no good, safe way to achieve what you're describing except persisting some data on an object and then hoping for the best. It's brittle, not type safe and just generally poor design.

With that said, I do agree that nextjs middleware is trash. My main issue with it is that I never use nextjs on vercel, always on node, but I'm still limited in what I can use in middleware because they're supposed to be edge-safe. Eye roll. They are apparently remedying this, but this sort of thing is typical for next.

I'm not sure I agree. Having multiple middlewares is a standard feature in many libraries/frameworks. Express (Node) has many middleware libraries to do a ton of stuff. Axum (in rust) also makes use of middlewares. You can argue that there's better way to do some of the things middlewares are used for, but then you're also arguing that literally everyone is holding it wrong.

I also don't think every other framework has the exact same issues. Take a look at SvelteKit for example.

You can add data from the middleware/hook into a locals object (https://svelte.dev/docs/kit/hooks#Server-hooks-locals). This is request scoped and accessible from the route handlers when needed. It also supports type definitions (https://svelte.dev/docs/kit/types#Locals). I wouldn't call this brittle. It's just dependency injection.

Note that it doesn't explicitly support multiple middlewares either (well, sort of; there's https://svelte.dev/docs/kit/faq#How-do-I-use-middleware but I think you're meant to be using hooks for your code https://svelte.dev/docs/kit/hooks#Server-hooks-handle), but at least it's easy to use and doesn't intentionally try to obfuscate information from you.

Edit: It seems that at some point sequence (https://svelte.dev/docs/kit/@sveltejs-kit-hooks#sequence) got added, so disregard the paragraph above.

> I would argue if you're trying to chain middleware or communicate between middleware, you're already holding it wrong.

I haven't kept up with Next.js idioms but in generat that's what middleware is for. It's implied in the name. Middleware-chaining is a common idiom.

It's the littke details that Next.js middleware intercommunicate over HTTP headers (?!) that makes it a different pattern.

> It's brittle, not type safe and just generally poor design.

Dotnet has no problem with that when using Minimal APIs.

Watch out, Lee is gonna show up and defend this decision and not respond to any valid criticisms.
I can't think of too many popular frameworks that DONT support multiple middleware. Yes you persist data through all the middleware if needed, that's the whole point
Javascript was never build for those use-cases. It should have stayed on the browser.
JavaScript has handled the concept of middleware for decades.
For a decade, since the intro of NodeJS
Sorry to inform you but you're off by about 6 years, nodejs was released about 16 years ago, and express has had middleware for 14 of those years.
Time flies... Thanks for the correction, buddy.