179 comments

[ 3.0 ms ] story [ 120 ms ] thread
I don't get these kind of complaints, coming from Java and .NET web frameworks, Next,js is the only sane frontend framework followed by Angular.

Saying this as someone doing Web related development since 1998, glory days of Perl and CGIs.

I’m guessing you enjoyed the nostalgia when you saw directory based path convention from the good old CGI days?
It really is. I am a staunch react defender, I work with it daily and I found the change from class components to hooks to be a better programming model.

But whenever I work with Next, I feel like we lost the plot somewhere. I try a lot of frameworks and I like esoteric programming languages, but somehow Next.js, the frontier JavaScript framework embraced by React is the only experience where half the time, I have no idea what it’s error messages (if I get any to begin with) are trying to tell me. I can’t even count the hours I spent with weird hydration issues.

Next has enshittifed themselves some time ago. Everything that goes through the VC cycle does that eventually.

I am happy for them and their money, but I can't use this anymore. I take Vite as the default option now, but I would prefer something more lightweight.

Heard and appreciate the feedback. We’re well aware of the DX papercuts in Middleware. With 15.5 we made a big step in supporting Node runtime[1] which addresses a slew of issues people have reported over time.

If I went back in time, I would have called it Routing Middleware or Routing Handler. A specific hook to intercept during the routing phase, which can be delivered to the CDN edge for specialized providers. It’s also a somewhat advanced escape hatch.

Since OP mentions logging, it’s worth noting that for instrumentation and observability we’ve embraced OpenTelemetry and have an instrumentation.ts convention[2]

[1] https://nextjs.org/blog/next-15-5#nodejs-middleware-stable

[2] https://nextjs.org/docs/app/api-reference/file-conventions/i...

Since you're here — I'll just pipe in.

Here in this article, the author, failing to comprehend the domain differences, is applying the same approach to call a function everywhere. Of course it won't work.

The fallacy of nextjs is attempting to blend function domains that are inherently different. Stop doing that and you will be fine. Documentation won't work, it will be just more confusing. Blending edge and ssr and node and client-side into one is a mess, and the attempt to achieve that only results in layers upon layers of redundant framework complexity.

First off, since the sentiment here is really negative, I'd like to say that next.js is actually really good for what it does. You've done a great job at building the software that powers millions of websites at this point.

I think a big part of the negative sentiment derives from the fact that detailed documentation and reference documentation almost non-existant. The documentation mostly tells you what exists, but not how to use them, how they get executed, common pitfalls and gotchas etc etc.

The documentation is written to be easy and friendly to newcomers, but is really missing the details and nuances of whatever execution context a given api is in and does not touch on derived complexities of using react in a server environment etc.

This is a trend across a lot of projects these days - often missing all the nuances and details - writing good documentation is really hard. Finding the balance between making things user friendly and detailed is hard.

Keep it up

Will vercel/next come up with an official policy on pages roter/API routes, will they be supported long term? If I start a next project I still use pages/API routes, because of several really really bad experiences with the app router.
Yeah, I was actually recommended the instrumentation route by a commenter on Reddit.

I spent a similar amount of time setting up opentelemetry with Next and while it would have been titled differently, I would have likely still written a blog post after this experience too.

This isn't your fault, but basically every opentelemetry package I had to setup is marked as experimental. This does not build confidence when pushing stuff to production.

Then, for the longest time I couldn't get the pino instrumentation working. I managed to figure it out eventually, but it was a pain.

First, pino has to be added to serverExternalPackages. If it's not, the OTel instrumentation does not work.

Second, the automatic instrumentation is extremely allergic to import order. And also for whatever reason, only the pino default export is instrumented. Again, this took a while to figure out.

Module local variables don't work how I would expect. I had to use globalThis instead.

And after all that I was still hit by this: https://github.com/vercel/next.js/issues/80445

It does work, but it was not great to set up. Granted, I went with the manual router (eg. not using vercel/otel).

> Since OP mentions logging [...] we’ve embraced OpenTelemetry

I really hate this stuff. Users raise feedback for something they need, the dev team considers the feedback, they spend a really long time thinking about the most perfect abstraction, scope the problem way out to some big fundamental system, and come up with an extremely complicated solution that is "best". The purist committee-approved solution could technically be used to address what the user asked for, with a lot of work, but that's no longer the focus. Pragmatism goes out the window; it's all about inventing fun abstract puzzles.

All the while, the user just wanted to log things.

Not saying that's the exact situation here, but the phrasing in the comment was all too real to me.

I like it. I have been involved in software development for 20+ years - Perl, PHP, Java, Pyhon. And Nextjs and React gave me back the joy to develop web frontend again.

There are a lot of gotchas and considerations with Nextjs, but it is a framework and it is not unexpected that unless it is developed by yourself, frameworks require some getting used to.

There are some things that could be better, especially in non-Vercel-hosted scenarios, and if the backend for frontend part becomes too complicated, I would switch to Nest.js, but overall I am satisfied with Next.

as a Rails dev this makes me LOL. I would have expected the rube goldburg machine of JS frameworks to be more robust and ergonomic by now, but it looks more to be hacks built on top of hacks with no real vision or technical leadership.
RoR wasn't picked up by e-commerce at this scale. Most of the craziness comes from attempting to squeeze out every last inch of performance so that the prospective client won't go "neeeih" and shop somewhere else.

A RoR app will just sit comfortably wherever you deploy it, slowly doing its job like a good, reliable tractor.

A typical Next.js app is smeared all across its origin, some geographically convenient Edge and the frontend. It's a very different use case.

Remix (cough react router 7 framework mode cough) is like the polar opposite of this, it's just a Request -> Response handler that you have to build your server around manually. Which I found kind of annoying at first but it does give you the freedom to do what you want.
RRv7 is great. It does the heavy lifting of what you'd use this kind of framework for in the first place (one codebase in one language - typescript - one "stack"/lib tree - that does both the server and the client rendering), handles routing, route modules, code splitting, bundling, etc. etc.

Having to know node (or other supported server) and needing to implement your server business logic from scratch (models, db access, caching layer with redis or something, etc. etc.) is not a weakness, it's a strength.

The thing that .net tried to do for like a decade and failed to (one stack for both the server and the client), see Blazor bullshit etc. is handled here. Imagine you need a modern web app or a shop or whatever and that means React. It just does. Your backend stack is PHP or Rails or Go or whatever. Now you have to somehow square the hydration circle which you can't do without it being a massive pita (as PHP renders a page on the backend in.. well.. PHP) so you end up passing the data manually in some blobs of jsons or whatever with each request (or even worse, side to it in some fetches) that then React initializes from on the client and it's a total mess. Not to mention that unless you render the page in both php and react (try to keep both outputs the same lmao), you'll only see the full app "on the client" meaning crawlers/bots/google have to run JS on all your pages or see nonsense ... yikes.

SSR with hydration is there for this reason. You render the same React tree both on the server and on the client. The hydration process itself is made much easier by RR and its infrastructure (automatic passing of data to the client). Hell, thanks to SSR you don't even have to have JS enabled on the client if you're using just basic web standarts (see RRv7 docs on progressive enhancement and state management) and the site will work. This means even crawlers without JS runtimes will be able to index your site.

Similar to Meteor.js, they've tried to abstract things that aren't really abstractable (is this even a word?).

It handles edge-cases extremely poorly, and when you have those scenarios, you either need to find a workaround (so code becomes ugly and painful to maintain) or give up.

I've worked with it for a project, gladly never again.

I'll extend my feedback about Node.JS backend. Look how many flavors: deno, bun... It's a mess.

Node.js a terrible platform for server-side in comparison to Java/C#(performance/stability) & Ruby/Python(dev speed).

The only reason it is successful is that everybody knows JS/TS. But just because everybody knows it is rarely a reason to use it.

The event loop is quite nice and easy to reason about, but that's all there's to it. It is single-threaded and comes with gotchas, with at the end being in my opinion a negative aspect of it.

Many other langs/platforms offer also an event loop for concurrency, but they aren't often used. In the end no matter how much we hate threads, they serve a great purpose that has been battle-tested for so many decades.

Unfortunately companies adopt programming languages based on hype and trends, rather than technical reasons.

Until when we will have people hyped up about writing web servers in CSS, even though it doesn't make any sense to?

TLDR: It isn't only Next.JS, but the whole NodeJS thing isn't that great.

When they transitioned to the app router it was like they'd given some bootcamp graduates a crack at "improving" on the express apis - which are mature and roughly align with the composable russion doll approach taken in servlets, rack, plug and any other server interface I've ever seen.

Aside from the abysmal middleware api you also have the dubious decision to replace having a request parameter with global functions like cookies() and headers().

Perhaps there is some underlying design constraint that I'm missing where all of these decisions make sense but it really does look like they threw out every hard fought lesson and decided to make every mistake again.

Half these issues stem from a relative misunderstanding of exactly where the code is running. Next.js has layers upon layers upon layers due to the interplay between the browser, middleware, edge vs. node, SSR... It's an enormous amount of complexity and it really only fits under the following set of circumstances:

  * You sell a B2C product to a potentially global audience, so edge semantics actually help with latency issues
  * You're willing to pay Vercel a high premium for them to host
  * You have no need for background task processing (Vercel directs you to marketplace/partner services), so your architecture never pushes you to host on another provider.
Otherwise, just tread the well-trod path and stick to either a react-vite SPA or something like Rails doing ordinary SSR.
As mentioned somewhere else, these are the kinds of layers SSR frameworks have had for decades, maybe people should learn not to do SPAs for everything.
I wouldn't say I agree with those circumstances, but even if they did indicate a match with Next.js, they are not worth the reduction in productivity and maintainability that comes with it.

I use Gleam's Lustre and am not looking back. Elm's founder had a really good case study keynote that Next.js is basically the opposite of:

https://www.youtube.com/watch?v=sl1UQXgtepE

> Otherwise, just tread the well-trod path and stick to either a react-vite SPA or something like Rails doing ordinary SSR.

Just write your SPA the grown up way. Write your APIs in a language and framework well suited to such work (pick your poison, Rails, Spring, whatever Microsoft is calling this year's .NET web technology). And write your front-end in Typescript.

There's absolutely no reason to tightly couple your front-end and backend, despite how many Javascript developers learned the word "isomorphic" in 2015.

> Half these issues stem from a relative misunderstanding of exactly where the code is running.

If I take a look at other languages, these kind of multi-threading issues are usually represented by providing a separate context or sync package (that handle mutexes and atomics) in the stdlib.

And I guess that's what's completely missing in nodejs and browser-side JS environments: An stdlib that allows to not fall into these traps, and which is kind of enforced for a better quality of downstream packages and libraries.

> Half these issues stem from a relative misunderstanding of exactly where the code is running.

I used to think Javascript everywhere was an advantage, and this is exactly why I now think it's a bad idea.

My company uses Inertia.js + Vue and it a significantly better experience. I still get all the power of modern frontend rendering but the overall architecture is so much simpler. The routing is 100% serverside and there's no need for a general API. (Note: Inertia works with React and Svelte too)

We tried Nuxt at first, but it was a shit show. You end up having _two_ servers instead of one: the actual backend server, and the server for your frontend. There was so much more complexity because we needed to figure out a bunch of craziness about where the code was actually being run.

Now it's dead simple. If it's PHP it's on the server. It's JS it's in the browser. Never needing to question that has been a huge boon for us.

Vercel is the cancer of the modern web. The claw into every framework ecosystem and abuse them as sales funnels for their paid plans, pretending they care about open source, competition, and the web.
> a relative misunderstanding of exactly where the code is running.

This is the exact problem with the App Router. It makes it extremely difficult to figure out where your code is running. The Pages Router didn't have this issue.

> so edge semantics actually help with latency issues

Hum... You make an entire app in node, load the UI over react, pile layers and more layers of dynamicity on top (IMO, if next.js didn't demonstrate those many layers, I wouldn't believe anybody made them work), eschew the standard CDN usage, and then want distributed execution to solve your latency issues?

Looks like we're all joining the anti next.js train especially as more and more vibe coded apps seem to be building on next.js!
The direction React and Next.js have been moving is to give you very granular control over where your code runs, and when.

The previous model was that you simply have code that runs on a server when a request comes in, sends a response to the client, and then the code in that response is run on the client. Instead, now we have a situation where some bits run on the server, some of them on the client, which call out to some bits on the server again, and all of this can happen either before or after the server started sending the response. And then on e.g. Vercel, you also have edge functions as an additional permutation.

Which is kinda neat, but also massively complicates the mental model.

I have a tendency to use different stuff on new projects for the sake of it. I've built apps with express + react on client, angular, vue, next, nuxt.. Used go, .net, node, php etc on the server. I always find good and bad parts and appreciate different aspects of different solutions.

Not Next though. We built a pretty large app on Next and it was painful from start to finish. Every part of it was either weird, slow, cumbersome or completely insane.

We still maintain the app and it is the only "thing" I hate with a passion at this point. I understand that the ecosystem is pretty good and people seem to be happy with the results given that it is extremely popular. But my own experience has been negative beyond redemption. It's weird.

When I first saw Next.js I was immediatelly reminded of Meteor.js. I did invest a bit in learning into it and did some personal projects. But quickly realized it was both over-abstracted and inflexible which made it really hard to get it past prototypes.

But these solutions keep coming up because they bring one thing: Self-contained / "batteries included". Just the other day there was a thread in hackernews about Laravel vs Symphony and it was the same thing: shit breaks once complexity comes in.

If you compare those solutions with the old model that made NodeJS / React SPA get so popular, so fast: Buffet-style tooling/libraries. You basically build your own swiss army knife out of spare parts. Since all the spare parts are self-contained they have to target really low abstraction levels (like React as a component library, HTTP+Express as a backend router, Postgres as DB).

This approach has many disadvantages but it really keeps things flexible and avoids tower-of-babel style over-engineering. As in a lot of layers stacked on top of each other. Not that the complexity goes away, but instead you have a lot of layers sibling to each other and it is more doable to replace one layer with another if things aren't working well.

It is understandable why "batteries included" is so popular, it is really annoying to stitch together a bunch of tools and libraries that are slightly incompatible with each other. It definitely needs people with more experience to set up everything.

> it is really annoying to stitch together a bunch of tools and libraries that are slightly incompatible with each other

This is my job. We're a small team and my job is to keep things up to date. Insanely time consuming. Packages with hard dependencies and packages that stopped being supported 5 years ago.

Nah, Laravel is proof that over engineered abstraction can sometimes be done right. Laravel works beautifully in production and I have never regretted using it.
Thing is I'm spoilt by asp.net, which has so much bad 'stigma' in the (esp startup) dev community but it is _extremely_ well designed.

You get a very batteries included approach(es) but you can always punch out of it and override it. I've never got into a situation where I'm feeling like I'm fighting the framework.

I also really like both Blazor Server and Blazor Webasm which allows you to write the frontend in C# too. Blazor server is great for internal admin panel style apps, and blazor webasm is good for saas apps, and for everything else plain old server sider rendering works great.

I'd really recommend anyone who is annoyed with their web framework to give it a go. It's extremely cross platform now (the huge drawback until about a decade ago was it was very hard to run on Linux, which isn't the case at all now - in fact, it's the opposite, harder to run on Windows), very fast and very easy to use. It takes a while to figure out the mental model of the design in your head but once it comes together you can quickly figure out how to override everything when you hit limitations (which tbh, is pretty rare compared to every other framework).

>both over-abstracted and inflexible which made it really hard

This seems to be built into the culture of companies which have those ridiculous whiteboard leetcode interviews. You find people who can produce very clever complex solutions in their sleeep, and then they do that. Interviews aren't selecting for people whose strength is simplicity and clarity instead. So you get a lot of tight loop optimizers and they tight loop optimize everything... not just the tight loops. But if your product is a library/framework being consumed by mere mortals, you probably want something simple if you want to succeed in the long run. The super car's performance is meaningless to you if you can't drive stick.

> It definitely needs people with more experience to set up everything

I mean it's not just the experience - it's the upfront time cost and then ongoing maintenance.. and for what? It's really easy to underestimate how much effort this will be

Having done both I genuinely think Rails is a 10x productivity boost over stitching your own mishmash of libraries together in Node

The only lack of flexibility you run into is if you really disagree with the fundamentals of the framework. If you hate the ActiveRecord pattern for example you need to stay away

"shit breaks once complexity comes in" is a skill issue

> If you compare those solutions with the old model that made NodeJS / React SPA get so popular, so fast: Buffet-style tooling/libraries. You basically build your own swiss army knife out of spare parts. Since all the spare parts are self-contained they have to target really low abstraction levels (like React as a component library, HTTP+Express as a backend router, Postgres as DB).

I have done a few Angular apps and the experience/setup quoted above is basically foreign to me. I know that it is a framework and not a library but it is a very well designed framework (atleast Angular 2 onwards; I used Angular v20 for my latest component). Basically most of the commonly needed stuff is included in the framework (I just added NGXLogger for logging) and the abstractions are pretty nice and fairly similar to a backend service (services wrap libraries and components rely on services). RxJS can be a bit of a learning curve but once you are comfortable with the basics, it can take you quite far. Atleast I rarely had to fight with the framework for typical SPAs. Also, the documentation along with tutorials is great - I learned using the tour of heroes application[0] but seems angular.dev[1] is the new home for v20 docs.

[0]: https://v17.angular.io/tutorial/tour-of-heroes

[1]: https://angular.dev/

Next.js is marketing to get you locked into vercel hosting.
Using nextjs for years without paying a cent to Vercel. If you want React SSR, why would you create a DIY solution if there is a framework with huge community and support?
They're trying to do something that's fundamentally very hard. Unifying server-side and client-side code was always going to cause confusion when the difference becomes relevant.

Personally I'd rather go in the direction of having code that's explicitly server-side, explicitly client-side, or explicitly shared utilities. But you'd need more of a type-safe mentality to take that approach, and you'd probably scare off the majority who prefer runtime errors over build-time errors.

Your observations apply generally. Debugging "magic" frameworks is often more complex than starting with simple basics and a coherent design. As a bonus there are less dependencies, less build issues and lighter pages or binaries.
Fully agree really enjoying TRPc for this.
Through a customer I've come into contact with InertiaJS. React with Laravel made my work so much simpler. Routing through Laravel was easier for me. The data sharing from Laravel to the frontend is painless.

I also like the server side, PHP works better for me than a Javascript server. I've had some weird bugs with nodemon, pm2 and other server tools.

I also recommend inertia.

It really doesn't do much, which is very refreshing coming from Nextjs.

It's simple tooling for backend for frontend-style APIs, taking care of basic routing, fetching of data, and submitting forms.

While inertia was invented for Laravel, I'd argue that it works even better with Adonisjs. Because Adonisjs is TypeScript you can infer the types coming from the backend.

+1 for this stack.

Adonis + Inertia works wonderfully well. It's the best of both worlds. And the simplicity of this architecture is something to admire. It's very easy to know what's going on at every point: It's just requests, responses, middlewares and routes/views. Simple and easy, while still super powerful.

Can't wait for the opinionated fork that gets abandoned in 3 weeks.
As much as I don't like most things about nextjs (I could write a vastly larger blogpost about it but won't as I like to keep my heartrate down), it feels like claude was trained specifically for it. In our experience, claude code is better at nextjs than other frameworks.
That seems like the most unfortunate of reasons to choose it as a framework for new projects, though. I hope that doesn't become the deciding factor in the future.
Significantly better than just React and a Node backend? I doubt it, what's the comparison here?
the interesting web problems (collaborative tools, creative software, scientific computing) have to fight against a framework ecosystem designed for the blandest landing pages.

Nextjs and most web frameworks assume you're building an e-commerce site that has to only differentiate on loading speeds.

React server components and server side rendering should never have been in react but instead should have lived its life as a separate project.
Absolutely! But that is not the first time React changes its core. For me, it is dead now.
Anyone who is running back-end code in Next.js has no idea what they are doing. It could be acceptable if it is a toy project and you want to get something quickly but even for a small operation or MVP, the whole thing is not coherent.

I've wrote previously about nextjs: https://omarabid.com/nextjs-vercel My opinion remains the same: Most of the issues in Nextjs are not a bug but a feature. A feature that only functions and locks you in Vercel platform.

Since their routing/SEO/content features are also now less functional, there is really very little reason to use Nextjs especially with React Server Components.

Modern development in a nutshell.

You want to use something full of abstractions to the point you have no idea how it actually worked.

You did this to save time.

Then when issues occur it's someone else's fault.

That said, let me pass in a flag to get my dev logs in prod. That's ultimately what the author wants.

I didn’t fully read the post, but pretty sure they have a good point. I inherited next.js on a project it is the absolute worst framework.

I don’t need/want to elaborate.

I convinced myself to hate App Router before even trying it because of all the negative sentiment on HN.

After using it in three production-scale projects now, I think it's a great isomorphic JS / TS framework. It's as close to a "batteries included" (such as Rails or Phoenix) system that the JS ecosystem has.

And yet, people generally like to shit on Next.js I sense because they haven't taken the small amount of time investment required to actually just understand it: which I fear is especially true if they came from Pages Router. This kind of fallacy appears to hold true in the OP -- bemoaning that you "can't have multiple middlewares or chain them either"... yes, you can? Sure, it's different from the Express way of doing things, but you absolutely can get it to do what you want.

Was Express ever _that_ easy before you actually understood it and knew what you were doing?

> Was Express ever _that_ easy before you actually understood it and knew what you were doing?

yes

also sails.js was the bomb.