I think the peak lunacy of the Next.js router is that the redirect function works by throwing an error to abuse the call stack. So much of their app router is built on top of side effects.
What's infuriating, is the basic idea of taking a language that was "designed" (and I am using the term very loosely here) to make <div>s in a browser window move, and shoehorning it into a language to write backend servers in.
This was NEVER a good idea, and no amount of "but but but JIT but but but node but but but talent pool! apologetism is EVER going to change that.
The worst part about backend JS? There never was a need to do that. Sure, JS is the only real option in the browser. I am okay with that. I can even make my peace with it.
But for backend? We had options long before node and all the other crap came floating along the drainpipe. Hell, even writing web apps in goddamn perl is better than this shit.
Don't believe me? Well, let's compare, shall we?
# perl
sleep(1)
# node
const sleep = t => new Promise(resolve => setTimeout(resolve, t))
await sleep(1000)
One of those is a programming language. Not a particularly well designed one, but absolutely serviceable. The other looks like something a contestant at an obfuscated coding contest might submit as an answer.
Ah yes. Some of the best arguments an engineer could make for a technical decision out here. "I don't like X because it's bad", "This very basic and totally non trivial example takes one line of code less in Y", "Z,C,V are better because I say so", "The backend is sacred", "It's blasphemy", "I don't like broccoli".
What's scary is that some engineers with 5+ YoE think like this. JavaScript has an alive community, arguably, the biggest one nowadays. We have multiple runtimes and engines going, if Node or V8 are not to your liking. Most modern projects use TypeScript with strict mode, or are using gradual typing. You can not like it. You can call out it's flaws, like it's quirks, the community, bad culture, packages, but you can't just ignore the elephant in the room. That it's a perfectly viable solution for production backends, even if you don't like it.
What's scary is that some engineers with 5+ YoE think like this.
It's scary that different people like different things?
What a scary world we live in.
JavaScript has an alive community, arguably, the biggest one nowadays.
Weeell, no. That would be the Python community.
And besides, a large part of the JS "Community" seems to be busy inventing ever new ways to not having to write Javascript. Since this doesn't really seem to happen with many other languages, weeeeeell...that tells me all I need to know what even large parts of the "community" around this trainwreck of a language think of it.
We have multiple runtimes and engines going, if Node or V8 are not to your liking
Cool, so, other than that I have...Deno, Bun, and...? Oh, that's it? Huh. Did you know that there are, like, 10 or 12 different Python runtimes? No, seriously! There is even one written in Rust.
Also, what makes you believe my rant is about any specific runtime? It's the language that's the problem.
That it's a perfectly viable solution for production backends, even if you don't like it.
And you will have to accept the fact that I don't like it, that I believe, with reasons, that JS is a shitty language, and that I will continue to voice my opinion on the subject.
The obvious advantage of the node way is that while this async sleep is paused, the process as whole could still do other tasks, such as respond to other async events. The perl process, in constrast, is entirely stuck and can execute nothing else while it executes that sleep. That oneliner is the kind of thing you actually write in the rare cases that you need to sleep in an async method, though I often compress it to "await new Promise(r => setTimeout(r, 1000))", or whatever.
Node.JS and JavaScript in general are substantially better than Perl in virtually every way, in my opinion, though it is only with TypeScript that it becomes actually nice to write. Still, the runtime for JS is like 10 times faster in practice, uses much less memory because it doesn't have the fat scalars and hashmaps, and has much nicer syntax to look at with far fewer symbols and rules to remember and understand. A case in point is that Perl is basically dead language whereas JS continues to be vibrant.
For my day job, I write Java and TypeScript. To be honest, I wish I had TypeScript on server side because it has structural type system and I find it more convenient to nominative typing. That being said, Java these days is also half-decent -- streams, lambdas, records and virtual threading has done a lot to revive it and the experience is relatively pleasant these days, though it's still far clumsier than TypeScript that remains my favorite of all languages I've ever used.
What holds me in Java are the libraries that I'm not easily willing to give up. I used to write Perl earlier in my career and one thing that really sucked about the language is that nobody implemented the standards I needed as Perl libraries, so interoperability with other systems often meant cooking my own minimal versions of standards that would have had ready to go .Net and Java implementations. Reading and augmenting PDFs, Excels, etc. also was a real chore. A language that is clearly dying out has an added friction, and Perl was surely dying in the 2000s already. So, I really found your comparison point rather bizarre.
The obvious advantage of the node way is that while this async sleep is paused, the process as whole could still do other tasks
Back when Chromium sped up some JSON serialization, I read a comment on HN about how, because JS doesn't support multithreading, they used JSON to transfer data between processes, and that turned out to consume a majority of the CPU time.
I have no clue about perl, I've never used it, but many other languages support multithreading and do not suffer from repeatedly serializing and deserializing strings...
So are you really making the argument that JavaShit is chosen because of its performance? My guess is that a C program could do a whole lot of actual work by the time you load up your massive node binary, load the source code, parse the source code, warm up the jit, jit the source code, run the jitted source code, just to sleep.
The obvious advantage of the node way is that while this async sleep is paused, the process as whole could still do other tasks, such as respond to other async events. The perl process, in constrast, is entirely stuck and can execute nothing else while it executes that sleep.
no, the thread is stuck, the fact that perl does not support multithreading is orthogonal
The obvious advantage of the node way is that while this async sleep is paused, the process as whole could still do other tasks, such as respond to other async events. The perl process, in constrast, is entirely stuck and can execute nothing else while it executes that sleep. That oneliner is the kind of thing you actually write in the rare cases that you need to sleep in an async method, though I often compress it to "await new Promise(r => setTimeout(r, 1000))", or whatever.
Any language that implements threading will also implement stack suspension, and your sleeps will permit doing other work on that same thread. Your argument is moot.
Great take here. Agreed the comparison to Perl was odd. I get the argument of “even a language like Perl can do this thing better”. But OP misses what JavaScript is actually doing under the covers. Try expressing non-preemptive cooperative multitasking in Perl (probably would need to use POE or Coro) and then compare that to JavaScript and see which one is more elegant.
I liked your post for other reasons also. It made me think about the death of a language and how it’s slow. You see less modules/libraries from the community over time. The language itself gets less updates and features. Things you need the language to do are awkward or difficult and take lots of effort. And it gets harder and harder to find jobs using that language.
Try expressing non-preemptive cooperative multitasking in Perl (probably would need to use POE or Coro) and then compare that to JavaScript and see which one is more elegant.
You'd probably use Mojolicious for this actually, though it's still going to turn into either a promise or a CPS callback at the end, just like with Node.
With Mojolicious, Perl is actually pretty close in elegance to earlier versions of ES5 (and brings a few things ECMAScript didn't get until later, like defined-or), though modern Javascript has a much cleaner integration of async / await. I do still greatly prefer Perl's documentation story over Javascript's.
But that doesn't change the issues Perl's had with developer mindshare though.
Still, the runtime for JS is like 10 times faster in practice
Sorry, I cannot hear you over the sound of my Go and Rust backends running circles around Javascript while also not requiring a hugeass runtime to pollute my prod containers 😎
Moving goalposts much? But since you keep switching languages, show me how you do similar kind of non-blocking sleep in Rust without using any external crates and in less code than the JS example.
While I am sympathetic to the core of what you are trying to say, those code snippets are not the same thing at all. Please learn the difference between a function which blocks the thread and a coroutine.
You do realize that the fact that I cannot block the thread if I want to block it, at least not in a sane manner, is the very thing that is getting poked fun at here, right?
const sleep = t => new Promise(resolve => setTimeout(resolve, t)) await sleep(1000)
That doesn't work the same as the Perl sleep(); you have to call your JS version of sleep() with await, and then you have to change your function that calls sleep() to be async, and then you have to change all callers of the function that calls await sleep() to be defined as async.
That doesn't do the same thing as the JavaScript one, as Perl sleep will block the whole process meaning that no work is being done during that one second. Meanwhile JS will keep processing incoming requests. So you're wrong, Perl is a lot worse than JS.
I never used Perl, but for what it's worth I assume you'd probably run it as a CGI script (like PHP), so it wouldn't really block anything other requests.
Sleeping in Perl basically blocks your entire process, so if you’re serving multiple users, those other guys are out of luck. These are not the same thing at all.
I doubt their point was that you're supposed to run sleep() on the backend, I'm pretty sure it was about verbosity and complexity of invocation and they picked sleep() for an absurd example of something that's supposed to be short/easy but becomes significantly less so with promises and event loops.
But even if that wasn't the case, there's plenty of frameworks that use synchronous execution for handling incoming requests, where a sleep() would indeed block that entire process - and they aren't inherently "worse" than JS because of that. Those frameworks typically spawn threads or child processes, so you maintain multi-request capabilities even though individual requests can block.
So while I don't know about perl in particular, the argument about "worse than JS [because of blocking]" is bollocks in a general sense.
As a matter of fact, it shouldn't really belong in browsers either.
As the web turned from a document delivery into a rich GUI application platform, JS should've been replaced with a language designed for THAT purpose a long time ago - with something like Flutter's Dart or QT's QML.
Those were designed for the job. JS wasn't. Yet we continue trying to fix it, putting hacks on top of hacks on top of hacks (read: JS frameworks) to make it work. But it continues to be a shitty experience to both devs and users because the foundation is loose shit.
Spreading this suboptimal, not-designed-for-the-job mess to the backend is just next level stupid.
JS should've been replaced with a language designed for THAT purpose a long time ago - with something like Flutter's Dart or QT's QML.
FWIW, QML uses extended JS for scripting too, and it's closer to a HTML/CSS replacement. I think it is an improvement over vanilla HTML/CSS/JS, but it doesn't fully solve the problem that generating and managing the DOM dynamically can get a bit annoying. It only reduces the visibility of the problem, so you don't need to do it as often. I think there is still room for improvement here, probably something inspired by immediate UIs, ie. interspersing UI with traditional control flow. (AFAIK React to some extent is that?)
I was with you somewhat up until you offered up Python as a serviceable backend language. I’d much rather write TS on the backend in bun than ever have to touch Python.
The thing people should ask themselves about TS is this: What does it say about a language (JS), that has such an amazing amount of brainpower invested into not having to use it?
I find nextjs to be the worst option except for all the other options. I like being able to write my whole project in typescript from frontend to infrastructure. I like the ease at which I can set up a project and get it going. For small projects the cheapness of AWS shines through. Prisma fits well with nextjs and i have a serverless database that works well as well. For 99% of my projects it's ideal. Yes there are things that aren't perfect about it but again welcome to software engineering.
Yeah seems more ideal for blogs and such. Faster load times seems to be the primary benefit. Maybe ill give it a swing next time I design a blog or something
I think you're using the term "collapse" to mean something specific that is not being communicated.
I've only been doing this 30 years and I've never seen dependency management "collapse" a project. I've rewritten LOTS of Java (and other languages) with newer abstractions and libraries. Technically, a project can't die to poor dependency management, but the build process can become too convoluted for someone to understand. You pair that with a lack of will to address technical debt and projects are sometimes abandoned.
Java only turned 30 years old back in May (it came out in 1995) and dependency injection was coined by Martin Fowler back in 2004. So no, no you haven't been doing this for 30 years.
I don't know how I misread that. Funny thing it hardly changes anything - Maven 1.0 came out in 2004. Before that you'd manually download jar files and add them into a class path. It was called "jar hell" and it absolutely wrecked projects. You had the application servers (websphere, weblogic, jboss) with no real way to deal with conflicting versions and it absolutely killed projects. Then you had Hibernate / Spring conflicts. And then there was OSGi which resulted in plenty of scrapped projects. Then you had the "logging wars". Then you had Gradle, which killed a number of Android projects in the 2010's. It's been a rocky road for Java.
They tend to have a lot of technical debt. It's just not obvious because they are glaciers and don't ever get updated until it's almost too late to do so.
Yup. Those projects survive by maintaining an older ecosystem even when it's no longer advisable to do so. They provide business value, but that doesn't necessarily mean they are optimal or even good from.an engineering standpoint (even if at one time they were). They don't get rebuilt or maintained until it's critically necessary, and sometimes by that time it's too late.
This is not always the case. But when it is, it's rough.
Usually the people who have built the ecosystem. It's often Microsoft, or Sun, or Oracle, or whatever foundation you're standing upon. They continually deprecate and update parts of the ecosystem, but you'll see projects that never migrate simply due to cost or business priorities.
Depends on the company culture. Last place was still on .NET Framework 4.8 whereas my current place is finishing the upgrade to .NET 9 this week. The main driving force is security vulnerabilities. The company really doesn't want to go through that again.
What security vulnerabilities are there in framework 4.8 that are fixed in 9? Microsoft is still maintaining security patches on 4.8 and will do so for a very long time. Unless you're talking about third party packages.
Uhm akshully it's aspx. That could get technical debt but this new framework will never be obsolete! For real this time. You know what? I'm just gonna say it. ASP.NET is gonna be so not-obsolete that it's the last .net web framework. The last one. Nothing's gonna replace it, ever, because it's just so well engineered. Like Windows 10, it's just gonna receive updates till the end of time.
That’s because with .net and Java you just end up pinning the service to a version when it breaks and then spend the next 10 years writing micro services around it instead of fixing it.
He's saying that technical debt is rarely addressed in those codebases (which ttend to be business/enterprise code). You don't tend to fix things - you tend to build around it until you can't anymore.
Conversely, JS projects may or may not collapse under technical debt, but they also tend to be in more active development over their lifetime.
To be fair, this is less language-dependent than it is industry-dependent. Engineering shops will generally deal with gechbical ddbr better than government, for instsnce.
It’s all anecdotal evidence for all of us. I’ve seen Java projects that were perfectly maintained, up to date on every standard, clean code and regular sessions of cleaning up technical debt, and on the other side NodeJS frameworks that were stuck on an ancient version of something because an update would’ve been a full rewrite. That said, Typescript has been hugely useful in making things better: most awful NodeJS projects I’ve seen were using normal JS.
It all comes down to competence (and time), but I will stand firmly on the opinion that Java and .NET make it easier for competent programmers to maintain projects.
Static analysis does make it easier to maintain amd refactor large codebases, and that's what people are really complaining about when they talk about dynamically-typed languages like Python and JS. The true value of Typescript isn't the types at all - it's static analysis of code (and intellisense).
Java and .NET have always had good static analysis tools available due to the nature of the languages and more importantly the tools around them. But as you said, competent developers can work with anything (given time). A language doesn't need to be compiled or have strong typing to be maintainable. These things just happen to make it easier to do static analysis of a large codebase.
A language doesn't need to be compiled or have strong typing to be maintainable. These things just happen to make it easier to do static analysis of a large codebase.
No not at all, how many Java 8 and win forms I still see in prod. Business’s aren’t interested in fixing them because a decade ago something broke and instead of prioritizing fixing it and updating they want more features, so you freeze it and to code around it.
You all just act like because you use x framework or y language that you are immune to the external factors that are the real culprit of technical debt. But please continue to tell me how .net solves tech debt and live in your land of make believe where PM’s and the business aren’t the real decision makers and it’s you.
There’s no technical solution for tech debt (as with most social problems).
The things you describe as happening can happen with any language, with any framework. But the NodeJS ecosystem is fundamentally more prone to breakage, deprecation and instability.
I agree though that architecting properly can help significantly, as well as being somewhat conservative about tech choices. I’d go further and say that it can be good to evaluate whether you actually need certain kinds of tech: I’ve found lifting ORMs a pain in several languages, and sometimes, the database usage in the project was so simple that going with a simpler solution (or just plain SQL with some support) would’ve been easier. But it’s hard to know that when a project is still in the early phase.
They all suck. That’s the takeaway. It is not a coincidence why Microsoft made so many frameworks without backwards compatibility and abandoned as well.
The only difference is that Microsoft can absorb the hit from frameworks failing.
It’s infuriating if you are not a guru level expert in it as well as react, cause honestly you’ll need both. I’m not an expert, and I’ve managed several engineering teams who are comprised of smart people who footgun themselves daily with these tools.
I do a lot of work in both JS/TS and C#. Sometimes I wish JS framework devs would take a page out of the ASP.NET Core book. No framework I've ever used is as thorough yet extensible; it can basically fit any use case with relative ease. Since even the internals are based on dependency injection, you can even swap out core functionality for your own version to make it do things it wasn't designed for, because it's literally designed for that.
Next.js on the other hand, and the overwhelming majority of JS frameworks, have much more limited feature sets by comparison combined with (and especially in Next's case) a very in-the-box model, i.e. it's difficult to impossible to do things outside of the box.
The problem is js itself. You can only do so much with a language that was never built for anything more than simple scripts on web pages.
That and low quality devs. Since majority of the inception of js was driven by the internet boom where loads of people picked up web stacks but then there was a surplus of web devs but no work.
Next.js is closer to Wordpress than it is to ASP.NET. A closer comparison would be Node.JS, which is in countless ways superior to ASP.NET when it comes to getting it to do things with a web server.
Have you tried Fastify? It’s not using the methodology of .NET (as someone mentioned, Nest.js is more on par with that, but it’s a lot of boilerplate with all the downsides of Typescript and non of the actual upsides of the object and strictly typed languages it’s based upon), a lot of people just use Fastify as an alternative to Express and don’t look at the features it comes with, but it’s extremely powerful when using json schemas (which can be used to automatically validate input/request parameters and scrub «extra» data from response/output data) with tight integration to OpenAPI. It also has insanely good and easy standardized error handling and folder/file based routing. Typescript support is also the best I’ve seen when you learn how to use it with the schema definitions and AJV. In addition JSON Schemas are language agnostic, so it’s a write once, use everywhere case.
Took me years to find an alternative/complimentary framework to that combination, it’s just well thought out and fast to develop with good safety and security guarantees and little boilerplate. It’s been our go to backend framework for a long time now. We also used Nuxt up until recently when Vercel got full monopoly on SSR’s, but never used the server capabilities as we liked static pages and separating the concerns of backend and frontend.
Only downside is that it uses Node.js/Javascript/Typescript. I wish other frameworks took more inspiration from Fastify… I’ve gone through .NET, Spring boot, Laravel, FastAPI, Poem, Gin, Echo and more, before I landed on Axum, and it still leaves a lot to be desired when thinking back to Fastify. I hate having to define data models twice in my code just for boilerplate and that’s somehow just accepted as «required». We need a better definition to data models that are language agnostic, that define the restrictions and policies around the data, similar to how CueLang works.
The ill fate of frontend has been the deep dig into the amorphous circles of hell where architectural principles were left at the top, and what is left are people screaming and running around, manufacturing new positions for problems that could be solved by a single person who's staring down from the open air watching the broken hell at the bottom.
I think the fundamental problem with Nest.js (and all other JS frameworks) is that they suffer from the lack of standard libraries and need to do everything.
A huge portion of the features in ASP.Net come from other existing Microsoft or System libraries which handle functionality like DI, Caching, Logging, Telemetry, Settings and these are all easy to use independently outside ASP.Net. There's a massive advantage when the problem is How do we implement this functionality in dotnet instead of How do we implement this for our framework
Including batteries is sort of the problem with ja, nest provides a solution to things like DI, Caching, logging... With Asp.Net the framework is using existing solutions that work the same in a console app, desktop application or even a mobile app.
"Do everything" type frameworks tend to feel convenient at the start but over time there's more pain.
The more fundamental issue is the lack of available metaprogramming that makes stuff like telemetry and DI automatic and not an ongoing maintenance burden for your developers that can be bypassed. You can bypass DI in Spring/.NET, but it's frankly easier not to; the inverse is true in Nest and all other JS/TS frameworks.
Nest.js has excellent support for websocket gateways, gRPC, caching modules, scheduled jobs, swagger, auth guards, dependency injection, and out of the box typescript. I switch between .NET and Net.js often, it almost feels no different.
What makes me peace is that uses another Anders' language, server side components resemble JSTL and .NET views, and I can get an excuse to use C++ addons, if V8 isn't up to stuff.
I think that if you really want it, you can find it. I've not had the opportunity to use it yet, but I've heard very good things about Nest. I've been told that it's very Laravel inspired and Laravel itself is getting heaps of praise thrown at it. Again, I'm not in a position to use Nest and I'm not a PHP or ASP.NET guy so I can't really tell you if it's what you're looking for, but people are trying to build proper backend solutions in the JS world.
That being said, I'm not necessarily mad that Next (or SvelteKit) isn't a good backend server. I don't think it needs to be. But, it absolutely has to give you proper escape hatches so that you can do what you need to do. Including integrating it into your real backend.
Next should never be anywhere close to your real backend. It shouldn't be your real backend and it shouldn't be integrated with it.
The easiest thing to do with Next is also arguably the most secure: make API calls from the Next backend to your actual backend and call them via server actions from your frontend. Next doesn't have to do anything but proxy out to your real API. If you have a single frontend, you can effectively just consider the Next server as your API gateway and take your API entirely off the public internet.
Under no circumstances would I ever deploy a Next app to production if it connected to a database directly itself. Absolutely not.
Nest.js is an amazing back-end framework. I thoroughly enjoy using it and will probably not switch back to .Net Core or other javascript back-ends anytime soon
For C#, ASP.NET Core is like Spring Boot (Spring Web) for Java. I'm curious, does Spring Boot have the same advantages as ASP.NET Core in this regard? After all, Java and C# are often seen as enterprise-grade backend programming technology stacks.
As someone who primarily worked in asp.net core - but has started using next.js a lot recently, as for some reason our customers want us to develop using it, despite otherwise having zero say or interest in our tech stack - god, I miss it.
ASP.Net Core is such a great stack to work with; It does exactly what you want it to, despite the language (C#) being quite unergonomic compared to TypeScript.
Spring and Quarkus, what they are now doing with Aspire already existed on them as well.
However I do like Next.js, it is the only JS/TS framework, where my Java/.NET souls feels at home, and Typescript is anyway where Anders is now having fun.
Vercel's philosophy has moved well past "opinionated" and is now smug. I'm opinionated about some things. I think some solutions are wrong and some solutions are right. The difference is when I write a system that has a given limitation that prevents someone from implementing things the way they want I'll help them find a way of getting the job done and admit that my solution isn't universal.
Vercel's philosophy has moved well past "opinionated" and is now smug.
Our way or the highway now.
Ever since Vercel bought the React team starting sometime 2021, everything in React is about Next. You want plain React? Nope you want Next. React is now all about NextfuckingJs.
The same is happening now in React Native. Expo (the company) is the Vercel in React Native. In React Native land , it's all about Expo, and if you want bare React Native... well they made sure it was going to be as painful as possible for the user.
Yeah I mean at this point all react has going for it is JSX. Gotta hand it to them it's the most user-friendly templating system. The virtual dom seems pointless at this point because browsers update plenty fast now, and server side rendering is just better done using any of the myriad ways we have of doing that. Next solves a problem that react created, which is that react can't handle ingesting an html fragment.
We are just generating strings. That's all we need to do. Just make strings. It doesn't need to be this complicated. I get that mobile apps are different, but for the web it's just HTML. A plain text document.
Always was. Why did we ever buy that it was faster.
We are just generating strings. That's all we need to do. Just make strings. It doesn't need to be this complicated. I get that mobile apps are different, but for the web it's just HTML.
You are due to meet htmx. I think you would like it.
All the “blazing fast” presentations in 2012 with 1000 records live updating on a page. Except the whole time I was like “how can this possibly be faster since you have to funnel all your data through the top?”
Their middleware implementation is indeed straight but there's already a clear way to do what they're trying to do: log a given request's path down to the `page` level.
Ok, this was definitely a good tip. That being said, if I would have gone down this road before I would have still written this post. It most likely would have been longer.
First off, half the node/browser opentelemetry ecosystem is experimental. Not a deal breaker, but still.
Second, if you don't add pino to serverExternalPackages the instrumentation just straight up won't work.
Third, the instrumentation is extremely allergic to import order. I think this might be documented somewhere, but it was not immediately obvious why it wasn't working.
If you want a unified logging API you need to use globalThis and switch the impl in instrumentation.js and instrumentation-client.js. Using module exports (or a module scoped var) won't work. On the server each import is either duplicated or the value is getting overwritten somehow. This was fun to debug.
And lastly, it's still buggy. Middleware and pages don't share traceId. https://github.com/vercel/next.js/issues/80445
Other than being a total pain to set up and it not working very well yet, it should suffice for now.
Interesting. I've seen that page before I think, but note that I'm not sure if it does exactly what I need. Open telemetry itself should be more than configurable enough though.
I'll try this and see if I can hack around this. That being said, I would like for all logging to be covered under a single API (middleware, API handlers, server components, client components on the server and client components on the client). I'm not sure if this will work properly in the browser.
As you know, Next.js is Vercel-optimized so it was designed to have code that runs in multiple environments, hence the challenge and why things like `AsyncLocalStorage` don't work.
I agree that it'd be nice to have a built-in API that just...works (for once) but I do think OTel is established enough that a specific Next implementation built by Vercel would be inferior anyway.
Notably, you between `instrumentation.js` and `instrumentation-client.js` you can get app-wide monitoring. Also, `instrumentation.js` only runs once, so I believe you should be able to initialize a logging client there and achieve your original goal of scoping it to each request
next.js is easily the most confusing and magical (in the worst way) framework I've used.
Add that to the fact that they choose to use webpack in 2025 (Choosing to spend millions creating an "improved" version of it instead of just use Vite, which is the standard) and you've got the most clear "Why do everyone choose to use this?" moment imaginable.
I hate how sometimes it takes so long to hot reload changes, while an app made with vite is basically instantaneous. I spent sometime thinking about migrating it since I don't take much advantage of next features, but I inherited this project like this.
The worst thing about NextJS is the documentation, or lack thereof.
Here’s how it usually goes: look up something from their docs, be redirected to a doc about their “Pages router”, oops no I need “app router”, click on “app router” button, page does not exist. What the fuck
Next.js middleware is infuriating and honestly baffling. I don’t think I’ve ever come across someone other than a Vercel employee claim that it’s good or reasonable in any way. It clearly exists in its current state to support Vercel’s serverless infrastructure.
I’m exhausted by Next.js. I was an early adopter of Server Components and Server Actions. We still have good things to say about Server Components; less good things to say about Server Actions. But Next.js itself has worn me down. Mystery crashes from its internals, an overly opinionated caching layer, a WIP build system, and new versions that add so many surprising new bugs and regressions that it’s hard to justify following their release schedule.
I’m not sure who the ideal Next.js user is anymore being “an organization that wants to go all-in on Vercel.” That ain’t us since we use containers. But so many orgs get burnt by Vercel that I can’t even tell who the ideal Vercel user is at this point.
I’m watching Tanstack Start very closely. Hoping to find a way to migrate when it’s ready. Moving away from Server Components will be challenging. Excited for everything that happens after that.
Yeah the middleware is a constant source of frustration when making anything more complex than a brochure page.
What's even more frustrating is that when you decide enough is enough and eject using a custom server, you still can't do anything about these issues.
There's talk of a middleware rework on the issue tracker, but unless they scrap the whole thing and allow you to actually take over the request and do your things it's not going to be any better.
Well good news then - as of Next.js 15.5 (mid-august), NodeJS middleware is considered stable. It's not ideal, but at least there should not be those WTF moments you describe. And yes, I also implemented logging before this got fixed :D
Using Node.js middleware fixes the pino logging issue (sometimes) but it doesn't fix AsyncLocalStorage or that you can't pass anything except headers. Or that you can only have one middleware.
AsyncLocalStorage - yeah, could not get it working.
One middleware only is true, but it only means you have to implement your own chaining / url filtering code. Something like https://medium.com/@0xTanzim/implementing-multiple-middleware-in-next-js-combining-nextauth-and-internationalization-28d5435d3187
when vite came out I just sodded it off 😅 SSG thru Jekyll and CSR/dynamic through vite/react which has suited most things, and since it's transpiled to html it's practically infinitely scalable (a bad metric for pet projects anyway!).
too opinionated framework. react gives you the freedom to do what you want with vites HMR. want middleware? we got it! it's called express.js 😅
For middleware I use Hono in nextjs and it works fine. What I personally don't like with nextjs is sever actions and the way it handles error. Cause everything just returns a status code of 200 like wtf? I like the way sveltekit solved this problem.
Background: I have extensive experience in both NextJS and SvelteKit.
I don't see why, in 2025, one would start a new project using NextJS. The developer experience is abysmal, and the eternal argument of "large community, lots of tooling" does not really stand up anymore. Do engineers feel like they are or can be more productive in NextJS?
SvelteKit is better all-round, it is simple to understand, performs really well and, guess what, it can be hosted on Vercel if that's your poison.
And honestly, if you're choosing to stick with React the tooling + libraries for React right now are extremely good that you don't need to reach for Next unless you have a really good use case for it.
Like as of 2025 most projects could probably get by with:
Tanstack Query (previously react query)
Tanstack Router/React Router
React Hook Form +zod (or whatever validation library you want)
Zustand (optional)
Your own backend written in whatever you want
Personally, with how increasingly complex Next has become I think it's becoming harder and harder to justify picking it for a lot of people or startups, especially if you're building SaaS platforms.
I am forced to use Next.js on projects with SEO requirements, and I have never hated a framework more than this one.
Next doesn't even let you access the Express request object.
That reason alone should convince any prospective developer to not use this framework, I have another dozen reasons locked and loaded for anyone still not sure.
I kinda understand why they'd want to heavily discourage access to underlying request object, since they want to make Next cross-platform that can run SSR on alternate runtimes like Deno or cloudflare workers. But prohibiting access altogether is a completely baffling decision.
I’ve tried next JS and found it infuriating, everything it does somehow is overly complicated… like adding in routing patterns to the file paths…. Why? Why reinvent the wheel, just use normal route based parameters. I’m sure a next JS dev will say that it’s somehow performant, Server side components rendering blah blah
But it ends up being an unmaintainable nightmare.
Now I just use vanilla React and Vite.js with Yarn. It’s simple, I can easily reason about and know what’s happening on the front end and I abstract as much complexity to my non JS backend to avoid that blight of a language when possible.
I’m hoping someday WASM is able to be a drop in replacement for everything JS is used for these days. It’s really fundamentally a broken language… for instance JS has asymmetric true tables. Insanity
I was very confused by most of the article as I'm using Ring where the whole point is to have an open map to let your middleware do whatever thing you need besides the standard stuff.
Pre-populate :foo with some data when /:foo/ is in the path,
establish a request context for logging, auth/authz of various sorts, user role/permission checks etc.
All i can say is that it’s very very slow and dev and has carried on in prod. It’s just terrible.
Disclaimer: i don’t know much about nextjs since i just took over the project but for example, our redirect takes 10+ seconds to load that the user may think our application froze.
tmetler@reddit
I think the peak lunacy of the Next.js router is that the redirect function works by throwing an error to abuse the call stack. So much of their app router is built on top of side effects.
Big_Combination9890@reddit
What's infuriating, is the basic idea of taking a language that was "designed" (and I am using the term very loosely here) to make
<div>
s in a browser window move, and shoehorning it into a language to write backend servers in.This was NEVER a good idea, and no amount of "but but but JIT but but but node but but but talent pool! apologetism is EVER going to change that.
The worst part about backend JS? There never was a need to do that. Sure, JS is the only real option in the browser. I am okay with that. I can even make my peace with it.
But for backend? We had options long before node and all the other crap came floating along the drainpipe. Hell, even writing web apps in goddamn perl is better than this shit.
Don't believe me? Well, let's compare, shall we?
One of those is a programming language. Not a particularly well designed one, but absolutely serviceable. The other looks like something a contestant at an obfuscated coding contest might submit as an answer.
Virtual-Chemist-7384@reddit
oldmanyellsatclouds.png
Electrical_Bat2866@reddit
Ah yes. Some of the best arguments an engineer could make for a technical decision out here. "I don't like X because it's bad", "This very basic and totally non trivial example takes one line of code less in Y", "Z,C,V are better because I say so", "The backend is sacred", "It's blasphemy", "I don't like broccoli".
What's scary is that some engineers with 5+ YoE think like this. JavaScript has an alive community, arguably, the biggest one nowadays. We have multiple runtimes and engines going, if Node or V8 are not to your liking. Most modern projects use TypeScript with strict mode, or are using gradual typing. You can not like it. You can call out it's flaws, like it's quirks, the community, bad culture, packages, but you can't just ignore the elephant in the room. That it's a perfectly viable solution for production backends, even if you don't like it.
Big_Combination9890@reddit
It's scary that different people like different things?
What a scary world we live in.
Weeell, no. That would be the Python community.
And besides, a large part of the JS "Community" seems to be busy inventing ever new ways to not having to write Javascript. Since this doesn't really seem to happen with many other languages, weeeeeell...that tells me all I need to know what even large parts of the "community" around this trainwreck of a language think of it.
Cool, so, other than that I have...Deno, Bun, and...? Oh, that's it? Huh. Did you know that there are, like, 10 or 12 different Python runtimes? No, seriously! There is even one written in Rust.
Also, what makes you believe my rant is about any specific runtime? It's the language that's the problem.
And you will have to accept the fact that I don't like it, that I believe, with reasons, that JS is a shitty language, and that I will continue to voice my opinion on the subject.
audioen@reddit
The obvious advantage of the node way is that while this async sleep is paused, the process as whole could still do other tasks, such as respond to other async events. The perl process, in constrast, is entirely stuck and can execute nothing else while it executes that sleep. That oneliner is the kind of thing you actually write in the rare cases that you need to sleep in an async method, though I often compress it to "await new Promise(r => setTimeout(r, 1000))", or whatever.
Node.JS and JavaScript in general are substantially better than Perl in virtually every way, in my opinion, though it is only with TypeScript that it becomes actually nice to write. Still, the runtime for JS is like 10 times faster in practice, uses much less memory because it doesn't have the fat scalars and hashmaps, and has much nicer syntax to look at with far fewer symbols and rules to remember and understand. A case in point is that Perl is basically dead language whereas JS continues to be vibrant.
For my day job, I write Java and TypeScript. To be honest, I wish I had TypeScript on server side because it has structural type system and I find it more convenient to nominative typing. That being said, Java these days is also half-decent -- streams, lambdas, records and virtual threading has done a lot to revive it and the experience is relatively pleasant these days, though it's still far clumsier than TypeScript that remains my favorite of all languages I've ever used.
What holds me in Java are the libraries that I'm not easily willing to give up. I used to write Perl earlier in my career and one thing that really sucked about the language is that nobody implemented the standards I needed as Perl libraries, so interoperability with other systems often meant cooking my own minimal versions of standards that would have had ready to go .Net and Java implementations. Reading and augmenting PDFs, Excels, etc. also was a real chore. A language that is clearly dying out has an added friction, and Perl was surely dying in the 2000s already. So, I really found your comparison point rather bizarre.
cake-day-on-feb-29@reddit
Back when Chromium sped up some JSON serialization, I read a comment on HN about how, because JS doesn't support multithreading, they used JSON to transfer data between processes, and that turned out to consume a majority of the CPU time.
I have no clue about perl, I've never used it, but many other languages support multithreading and do not suffer from repeatedly serializing and deserializing strings...
So are you really making the argument that JavaShit is chosen because of its performance? My guess is that a C program could do a whole lot of actual work by the time you load up your massive node binary, load the source code, parse the source code, warm up the jit, jit the source code, run the jitted source code, just to sleep.
Sopel97@reddit
no, the thread is stuck, the fact that perl does not support multithreading is orthogonal
Worth_Trust_3825@reddit
Any language that implements threading will also implement stack suspension, and your sleeps will permit doing other work on that same thread. Your argument is moot.
jonnyman9@reddit
Great take here. Agreed the comparison to Perl was odd. I get the argument of “even a language like Perl can do this thing better”. But OP misses what JavaScript is actually doing under the covers. Try expressing non-preemptive cooperative multitasking in Perl (probably would need to use POE or Coro) and then compare that to JavaScript and see which one is more elegant.
I liked your post for other reasons also. It made me think about the death of a language and how it’s slow. You see less modules/libraries from the community over time. The language itself gets less updates and features. Things you need the language to do are awkward or difficult and take lots of effort. And it gets harder and harder to find jobs using that language.
mpyne@reddit
You'd probably use Mojolicious for this actually, though it's still going to turn into either a promise or a CPS callback at the end, just like with Node.
With Mojolicious, Perl is actually pretty close in elegance to earlier versions of ES5 (and brings a few things ECMAScript didn't get until later, like defined-or), though modern Javascript has a much cleaner integration of async / await. I do still greatly prefer Perl's documentation story over Javascript's.
But that doesn't change the issues Perl's had with developer mindshare though.
p1zza_dog@reddit
get out of here with your reasonable and well-informed takes 😅
spaceneenja@reddit
Javascript-bad.jpg
Big_Combination9890@reddit
Sorry, I cannot hear you over the sound of my Go and Rust backends running circles around Javascript while also not requiring a hugeass runtime to pollute my prod containers 😎
FINDarkside@reddit
Moving goalposts much? But since you keep switching languages, show me how you do similar kind of non-blocking sleep in Rust without using any external crates and in less code than the JS example.
TheWix@reddit
I loath JS with a passion and its ecosystem, but I'll take Typescript's type system over Go's. Would love to try Rust.
globalaf@reddit
While I am sympathetic to the core of what you are trying to say, those code snippets are not the same thing at all. Please learn the difference between a function which blocks the thread and a coroutine.
Big_Combination9890@reddit
You do realize that the fact that I cannot block the thread if I want to block it, at least not in a sane manner, is the very thing that is getting poked fun at here, right?
Fresh-Manner9641@reddit
In the real world why would you ever want to block a thread on a web server?
well-litdoorstep112@reddit
To make a fake progress bar, obviously. How else would you generate Minecraft gift codes? (Or idk, free robux, whatever kids these days want)
lelanthran@reddit
That doesn't work the same as the Perl
sleep()
; you have to call your JS version ofsleep()
withawait
, and then you have to change your function that callssleep()
to be async, and then you have to change all callers of the function that callsawait sleep()
to be defined as async.Not the same as Perl.
Big_Combination9890@reddit
You're right, it's alot worse than perl.
FINDarkside@reddit
That doesn't do the same thing as the JavaScript one, as Perl sleep will block the whole process meaning that no work is being done during that one second. Meanwhile JS will keep processing incoming requests. So you're wrong, Perl is a lot worse than JS.
cdb_11@reddit
I never used Perl, but for what it's worth I assume you'd probably run it as a CGI script (like PHP), so it wouldn't really block anything other requests.
superluminary@reddit
Sleeping in Perl basically blocks your entire process, so if you’re serving multiple users, those other guys are out of luck. These are not the same thing at all.
cdb_11@reddit
The only difference is who does the scheduling, more or less.
FINDarkside@reddit
Sure, depends on framework you use, if any. The most popular one is event loop based so sleeping would block processing other stuff.
VikingFjorden@reddit
I doubt their point was that you're supposed to run
sleep()
on the backend, I'm pretty sure it was about verbosity and complexity of invocation and they pickedsleep()
for an absurd example of something that's supposed to be short/easy but becomes significantly less so with promises and event loops.But even if that wasn't the case, there's plenty of frameworks that use synchronous execution for handling incoming requests, where a
sleep()
would indeed block that entire process - and they aren't inherently "worse" than JS because of that. Those frameworks typically spawn threads or child processes, so you maintain multi-request capabilities even though individual requests can block.So while I don't know about perl in particular, the argument about "worse than JS [because of blocking]" is bollocks in a general sense.
adamsdotnet@reddit
As a matter of fact, it shouldn't really belong in browsers either.
As the web turned from a document delivery into a rich GUI application platform, JS should've been replaced with a language designed for THAT purpose a long time ago - with something like Flutter's Dart or QT's QML.
Those were designed for the job. JS wasn't. Yet we continue trying to fix it, putting hacks on top of hacks on top of hacks (read: JS frameworks) to make it work. But it continues to be a shitty experience to both devs and users because the foundation is loose shit.
Spreading this suboptimal, not-designed-for-the-job mess to the backend is just next level stupid.
superluminary@reddit
JS with its callbacks, built in event loop and closure everywhere was absolutely designed for asynchronous user actions.
cdb_11@reddit
FWIW, QML uses extended JS for scripting too, and it's closer to a HTML/CSS replacement. I think it is an improvement over vanilla HTML/CSS/JS, but it doesn't fully solve the problem that generating and managing the DOM dynamically can get a bit annoying. It only reduces the visibility of the problem, so you don't need to do it as often. I think there is still room for improvement here, probably something inspired by immediate UIs, ie. interspersing UI with traditional control flow. (AFAIK React to some extent is that?)
poemehardbebe@reddit
I was with you somewhat up until you offered up Python as a serviceable backend language. I’d much rather write TS on the backend in bun than ever have to touch Python.
Big_Combination9890@reddit
The thing people should ask themselves about TS is this: What does it say about a language (JS), that has such an amazing amount of brainpower invested into not having to use it?
poemehardbebe@reddit
I didn’t say I think that JS is great, I said I rather use TS than Python.
Beli_Mawrr@reddit
I find nextjs to be the worst option except for all the other options. I like being able to write my whole project in typescript from frontend to infrastructure. I like the ease at which I can set up a project and get it going. For small projects the cheapness of AWS shines through. Prisma fits well with nextjs and i have a serverless database that works well as well. For 99% of my projects it's ideal. Yes there are things that aren't perfect about it but again welcome to software engineering.
_x_oOo_x_@reddit
Is it worse than Astro though?
Beli_Mawrr@reddit
Never used astro. What is it?
_x_oOo_x_@reddit
https://astro.build/
Supposedly a better framework, seems quite trendy at the moment, also haven't used it for anything non-trivial
Beli_Mawrr@reddit
Yeah seems more ideal for blogs and such. Faster load times seems to be the primary benefit. Maybe ill give it a swing next time I design a blog or something
daedalis2020@reddit
I have seen more JS backend projects collapse under technical debt than should be possible by professional teams.
I almost never see that happen in .NET or Java.
RunWithSharpStuff@reddit
What? Java projects regularly collapse due to poor dependency management all the time.
carefactor3zero@reddit
I think you're using the term "collapse" to mean something specific that is not being communicated.
I've only been doing this 30 years and I've never seen dependency management "collapse" a project. I've rewritten LOTS of Java (and other languages) with newer abstractions and libraries. Technically, a project can't die to poor dependency management, but the build process can become too convoluted for someone to understand. You pair that with a lack of will to address technical debt and projects are sometimes abandoned.
CherryLongjump1989@reddit
Java only turned 30 years old back in May (it came out in 1995) and dependency injection was coined by Martin Fowler back in 2004. So no, no you haven't been doing this for 30 years.
silhnow@reddit
But dependency management and dependency injection are different things.
CherryLongjump1989@reddit
I don't know how I misread that. Funny thing it hardly changes anything - Maven 1.0 came out in 2004. Before that you'd manually download jar files and add them into a class path. It was called "jar hell" and it absolutely wrecked projects. You had the application servers (websphere, weblogic, jboss) with no real way to deal with conflicting versions and it absolutely killed projects. Then you had Hibernate / Spring conflicts. And then there was OSGi which resulted in plenty of scrapped projects. Then you had the "logging wars". Then you had Gradle, which killed a number of Android projects in the 2010's. It's been a rocky road for Java.
lunchmeat317@reddit
Have you worked with a lot of enterprise code?
They tend to have a lot of technical debt. It's just not obvious because they are glaciers and don't ever get updated until it's almost too late to do so.
daedalis2020@reddit
You mean the apps that chug along working for decades? Yeah.
CherryLongjump1989@reddit
The word "working" is doing a lot of heavy lifting there.
lunchmeat317@reddit
Yup. Those projects survive by maintaining an older ecosystem even when it's no longer advisable to do so. They provide business value, but that doesn't necessarily mean they are optimal or even good from.an engineering standpoint (even if at one time they were). They don't get rebuilt or maintained until it's critically necessary, and sometimes by that time it's too late.
This is not always the case. But when it is, it's rough.
ILikeBumblebees@reddit
Who's doing this "advising"?
lunchmeat317@reddit
Usually the people who have built the ecosystem. It's often Microsoft, or Sun, or Oracle, or whatever foundation you're standing upon. They continually deprecate and update parts of the ecosystem, but you'll see projects that never migrate simply due to cost or business priorities.
Trident_True@reddit
Depends on the company culture. Last place was still on .NET Framework 4.8 whereas my current place is finishing the upgrade to .NET 9 this week. The main driving force is security vulnerabilities. The company really doesn't want to go through that again.
SeanMWalker@reddit
What security vulnerabilities are there in framework 4.8 that are fixed in 9? Microsoft is still maintaining security patches on 4.8 and will do so for a very long time. Unless you're talking about third party packages.
card-board-board@reddit
Try to get your child's grades on a public school system .NET website and you will delete this.
Cyral@reddit
The current state of .NET is a lot different from the 2005 aspx applications that still exist out there
well-litdoorstep112@reddit
🤓🤓🤓
poemehardbebe@reddit
That’s because with .net and Java you just end up pinning the service to a version when it breaks and then spend the next 10 years writing micro services around it instead of fixing it.
PolarBearSequence@reddit
This is ironic, right? You’re not really claiming NodeJS manages backwards compatibility better than Java or .NET?
lunchmeat317@reddit
He's saying that technical debt is rarely addressed in those codebases (which ttend to be business/enterprise code). You don't tend to fix things - you tend to build around it until you can't anymore.
Conversely, JS projects may or may not collapse under technical debt, but they also tend to be in more active development over their lifetime.
To be fair, this is less language-dependent than it is industry-dependent. Engineering shops will generally deal with gechbical ddbr better than government, for instsnce.
PolarBearSequence@reddit
It’s all anecdotal evidence for all of us. I’ve seen Java projects that were perfectly maintained, up to date on every standard, clean code and regular sessions of cleaning up technical debt, and on the other side NodeJS frameworks that were stuck on an ancient version of something because an update would’ve been a full rewrite. That said, Typescript has been hugely useful in making things better: most awful NodeJS projects I’ve seen were using normal JS.
It all comes down to competence (and time), but I will stand firmly on the opinion that Java and .NET make it easier for competent programmers to maintain projects.
lunchmeat317@reddit
Static analysis does make it easier to maintain amd refactor large codebases, and that's what people are really complaining about when they talk about dynamically-typed languages like Python and JS. The true value of Typescript isn't the types at all - it's static analysis of code (and intellisense).
Java and .NET have always had good static analysis tools available due to the nature of the languages and more importantly the tools around them. But as you said, competent developers can work with anything (given time). A language doesn't need to be compiled or have strong typing to be maintainable. These things just happen to make it easier to do static analysis of a large codebase.
PolarBearSequence@reddit
A strong type system is the best static analysis possible.
lunchmeat317@reddit
We're not in disagreement.
poemehardbebe@reddit
No not at all, how many Java 8 and win forms I still see in prod. Business’s aren’t interested in fixing them because a decade ago something broke and instead of prioritizing fixing it and updating they want more features, so you freeze it and to code around it.
You all just act like because you use x framework or y language that you are immune to the external factors that are the real culprit of technical debt. But please continue to tell me how .net solves tech debt and live in your land of make believe where PM’s and the business aren’t the real decision makers and it’s you.
PolarBearSequence@reddit
There’s no technical solution for tech debt (as with most social problems).
The things you describe as happening can happen with any language, with any framework. But the NodeJS ecosystem is fundamentally more prone to breakage, deprecation and instability.
poemehardbebe@reddit
If you are going to make that assertion you have to back that up.
PolarBearSequence@reddit
I mean… we’re all arguing anecdotes here.
I agree though that architecting properly can help significantly, as well as being somewhat conservative about tech choices. I’d go further and say that it can be good to evaluate whether you actually need certain kinds of tech: I’ve found lifting ORMs a pain in several languages, and sometimes, the database usage in the project was so simple that going with a simpler solution (or just plain SQL with some support) would’ve been easier. But it’s hard to know that when a project is still in the early phase.
azhder@reddit
They all suck. That’s the takeaway. It is not a coincidence why Microsoft made so many frameworks without backwards compatibility and abandoned as well.
The only difference is that Microsoft can absorb the hit from frameworks failing.
PolarBearSequence@reddit
They do, all in their own way, but: having used all three, NodeJS is by far the worst when it comes to stability and longevity of the ecosystem.
jimbojsb@reddit
It’s infuriating if you are not a guru level expert in it as well as react, cause honestly you’ll need both. I’m not an expert, and I’ve managed several engineering teams who are comprised of smart people who footgun themselves daily with these tools.
Cualkiera67@reddit
They weren't that smart then
Souseisekigun@reddit
Modern equivalent of "C is dangerous? Uhh just write good C then?"
drawkbox@reddit
Next.js is a behemoth, I prefer lightweight like Lit.
Key-Celebration-1481@reddit
I do a lot of work in both JS/TS and C#. Sometimes I wish JS framework devs would take a page out of the ASP.NET Core book. No framework I've ever used is as thorough yet extensible; it can basically fit any use case with relative ease. Since even the internals are based on dependency injection, you can even swap out core functionality for your own version to make it do things it wasn't designed for, because it's literally designed for that.
Next.js on the other hand, and the overwhelming majority of JS frameworks, have much more limited feature sets by comparison combined with (and especially in Next's case) a very in-the-box model, i.e. it's difficult to impossible to do things outside of the box.
khsh01@reddit
The problem is js itself. You can only do so much with a language that was never built for anything more than simple scripts on web pages.
That and low quality devs. Since majority of the inception of js was driven by the internet boom where loads of people picked up web stacks but then there was a surplus of web devs but no work.
CherryLongjump1989@reddit
Next.js is closer to Wordpress than it is to ASP.NET. A closer comparison would be Node.JS, which is in countless ways superior to ASP.NET when it comes to getting it to do things with a web server.
Givemeurcookies@reddit
Have you tried Fastify? It’s not using the methodology of .NET (as someone mentioned, Nest.js is more on par with that, but it’s a lot of boilerplate with all the downsides of Typescript and non of the actual upsides of the object and strictly typed languages it’s based upon), a lot of people just use Fastify as an alternative to Express and don’t look at the features it comes with, but it’s extremely powerful when using json schemas (which can be used to automatically validate input/request parameters and scrub «extra» data from response/output data) with tight integration to OpenAPI. It also has insanely good and easy standardized error handling and folder/file based routing. Typescript support is also the best I’ve seen when you learn how to use it with the schema definitions and AJV. In addition JSON Schemas are language agnostic, so it’s a write once, use everywhere case.
Took me years to find an alternative/complimentary framework to that combination, it’s just well thought out and fast to develop with good safety and security guarantees and little boilerplate. It’s been our go to backend framework for a long time now. We also used Nuxt up until recently when Vercel got full monopoly on SSR’s, but never used the server capabilities as we liked static pages and separating the concerns of backend and frontend.
Only downside is that it uses Node.js/Javascript/Typescript. I wish other frameworks took more inspiration from Fastify… I’ve gone through .NET, Spring boot, Laravel, FastAPI, Poem, Gin, Echo and more, before I landed on Axum, and it still leaves a lot to be desired when thinking back to Fastify. I hate having to define data models twice in my code just for boilerplate and that’s somehow just accepted as «required». We need a better definition to data models that are language agnostic, that define the restrictions and policies around the data, similar to how CueLang works.
ohx@reddit
The ill fate of frontend has been the deep dig into the amorphous circles of hell where architectural principles were left at the top, and what is left are people screaming and running around, manufacturing new positions for problems that could be solved by a single person who's staring down from the open air watching the broken hell at the bottom.
well-litdoorstep112@reddit
Or maybe, just maybe, UI is a hard problem.
ohx@reddit
No, bad design has nothing to do with UI being a hard problem. If anything, good design makes hard problems easier to address.
Atraac@reddit
Nest.js is close, heavily inspired by .NET, I actually like using it as a .NET/Node backend dev. I also heavily dislike Next.js
Fresh-Manner9641@reddit
I think the fundamental problem with Nest.js (and all other JS frameworks) is that they suffer from the lack of standard libraries and need to do everything.
A huge portion of the features in ASP.Net come from other existing Microsoft or System libraries which handle functionality like DI, Caching, Logging, Telemetry, Settings and these are all easy to use independently outside ASP.Net. There's a massive advantage when the problem is
How do we implement this functionality in dotnet
instead ofHow do we implement this for our framework
Atraac@reddit
Nest does include a lot of batteries or makes it easy to integrate with most popular libraries so I don’t feel like that’s an issue though
Fresh-Manner9641@reddit
Including batteries is sort of the problem with ja, nest provides a solution to things like DI, Caching, logging... With Asp.Net the framework is using existing solutions that work the same in a console app, desktop application or even a mobile app.
"Do everything" type frameworks tend to feel convenient at the start but over time there's more pain.
oorza@reddit
The more fundamental issue is the lack of available metaprogramming that makes stuff like telemetry and DI automatic and not an ongoing maintenance burden for your developers that can be bypassed. You can bypass DI in Spring/.NET, but it's frankly easier not to; the inverse is true in Nest and all other JS/TS frameworks.
dustingibson@reddit
Nest.js has excellent support for websocket gateways, gRPC, caching modules, scheduled jobs, swagger, auth guards, dependency injection, and out of the box typescript. I switch between .NET and Net.js often, it almost feels no different.
pjmlp@reddit
What makes me peace is that uses another Anders' language, server side components resemble JSTL and .NET views, and I can get an excuse to use C++ addons, if V8 isn't up to stuff.
Dminik@reddit (OP)
I think that if you really want it, you can find it. I've not had the opportunity to use it yet, but I've heard very good things about Nest. I've been told that it's very Laravel inspired and Laravel itself is getting heaps of praise thrown at it. Again, I'm not in a position to use Nest and I'm not a PHP or ASP.NET guy so I can't really tell you if it's what you're looking for, but people are trying to build proper backend solutions in the JS world.
That being said, I'm not necessarily mad that Next (or SvelteKit) isn't a good backend server. I don't think it needs to be. But, it absolutely has to give you proper escape hatches so that you can do what you need to do. Including integrating it into your real backend.
oorza@reddit
Next should never be anywhere close to your real backend. It shouldn't be your real backend and it shouldn't be integrated with it.
The easiest thing to do with Next is also arguably the most secure: make API calls from the Next backend to your actual backend and call them via server actions from your frontend. Next doesn't have to do anything but proxy out to your real API. If you have a single frontend, you can effectively just consider the Next server as your API gateway and take your API entirely off the public internet.
Under no circumstances would I ever deploy a Next app to production if it connected to a database directly itself. Absolutely not.
stillusegoto@reddit
Loopback.io v4 comes pretty close
shellpad_interactive@reddit
Nest.js is an amazing back-end framework. I thoroughly enjoy using it and will probably not switch back to .Net Core or other javascript back-ends anytime soon
YangLorenzo@reddit
For C#, ASP.NET Core is like Spring Boot (Spring Web) for Java. I'm curious, does Spring Boot have the same advantages as ASP.NET Core in this regard? After all, Java and C# are often seen as enterprise-grade backend programming technology stacks.
modernkennnern@reddit
As someone who primarily worked in asp.net core - but has started using next.js a lot recently, as for some reason our customers want us to develop using it, despite otherwise having zero say or interest in our tech stack - god, I miss it.
ASP.Net Core is such a great stack to work with; It does exactly what you want it to, despite the language (C#) being quite unergonomic compared to TypeScript.
pjmlp@reddit
Spring and Quarkus, what they are now doing with Aspire already existed on them as well.
However I do like Next.js, it is the only JS/TS framework, where my Java/.NET souls feels at home, and Typescript is anyway where Anders is now having fun.
Somepotato@reddit
Look at Nuxt. Particular, it's layers and modules which make it very extensible.
induality@reddit
You may have confused next.js with nest.js
card-board-board@reddit
Vercel's philosophy has moved well past "opinionated" and is now smug. I'm opinionated about some things. I think some solutions are wrong and some solutions are right. The difference is when I write a system that has a given limitation that prevents someone from implementing things the way they want I'll help them find a way of getting the job done and admit that my solution isn't universal.
Strong-Reveal8923@reddit
Our way or the highway now.
Ever since Vercel bought the React team starting sometime 2021, everything in React is about Next. You want plain React? Nope you want Next. React is now all about NextfuckingJs.
The same is happening now in React Native. Expo (the company) is the Vercel in React Native. In React Native land , it's all about Expo, and if you want bare React Native... well they made sure it was going to be as painful as possible for the user.
card-board-board@reddit
Yeah I mean at this point all react has going for it is JSX. Gotta hand it to them it's the most user-friendly templating system. The virtual dom seems pointless at this point because browsers update plenty fast now, and server side rendering is just better done using any of the myriad ways we have of doing that. Next solves a problem that react created, which is that react can't handle ingesting an html fragment.
We are just generating strings. That's all we need to do. Just make strings. It doesn't need to be this complicated. I get that mobile apps are different, but for the web it's just HTML. A plain text document.
chat-lu@reddit
Always was. Why did we ever buy that it was faster.
You are due to meet htmx. I think you would like it.
zenware@reddit
All the “blazing fast” presentations in 2012 with 1000 records live updating on a page. Except the whole time I was like “how can this possibly be faster since you have to funnel all your data through the top?”
femio@reddit
Most of OP's problems are solved by Next.js' OTel implementation. https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation
Their middleware implementation is indeed straight but there's already a clear way to do what they're trying to do: log a given request's path down to the `page` level.
Dminik@reddit (OP)
Ok, this was definitely a good tip. That being said, if I would have gone down this road before I would have still written this post. It most likely would have been longer.
First off, half the node/browser opentelemetry ecosystem is experimental. Not a deal breaker, but still.
Second, if you don't add pino to serverExternalPackages the instrumentation just straight up won't work.
Third, the instrumentation is extremely allergic to import order. I think this might be documented somewhere, but it was not immediately obvious why it wasn't working.
If you want a unified logging API you need to use globalThis and switch the impl in instrumentation.js and instrumentation-client.js. Using module exports (or a module scoped var) won't work. On the server each import is either duplicated or the value is getting overwritten somehow. This was fun to debug.
And lastly, it's still buggy. Middleware and pages don't share traceId. https://github.com/vercel/next.js/issues/80445
Other than being a total pain to set up and it not working very well yet, it should suffice for now.
dangerbird2@reddit
For logging, the easiest solution is to skip next-native middleware altogether and use a custom app with expressjs logging middleware that Just Works
Dminik@reddit (OP)
Interesting. I've seen that page before I think, but note that I'm not sure if it does exactly what I need. Open telemetry itself should be more than configurable enough though.
I'll try this and see if I can hack around this. That being said, I would like for all logging to be covered under a single API (middleware, API handlers, server components, client components on the server and client components on the client). I'm not sure if this will work properly in the browser.
femio@reddit
As you know, Next.js is Vercel-optimized so it was designed to have code that runs in multiple environments, hence the challenge and why things like `AsyncLocalStorage` don't work.
I agree that it'd be nice to have a built-in API that just...works (for once) but I do think OTel is established enough that a specific Next implementation built by Vercel would be inferior anyway.
Notably, you between `instrumentation.js` and `instrumentation-client.js` you can get app-wide monitoring. Also, `instrumentation.js` only runs once, so I believe you should be able to initialize a logging client there and achieve your original goal of scoping it to each request
modernkennnern@reddit
next.js is easily the most confusing and magical (in the worst way) framework I've used.
Add that to the fact that they choose to use webpack in 2025 (Choosing to spend millions creating an "improved" version of it instead of just use Vite, which is the standard) and you've got the most clear "Why do everyone choose to use this?" moment imaginable.
powerhcm8@reddit
I hate how sometimes it takes so long to hot reload changes, while an app made with vite is basically instantaneous. I spent sometime thinking about migrating it since I don't take much advantage of next features, but I inherited this project like this.
chat-lu@reddit
That's because vite doesn't bundle anything, it sends the various files on the fly as they are requested.
driftking428@reddit
And then you company demands you use npm on top of it.
witness_smile@reddit
The worst thing about NextJS is the documentation, or lack thereof.
Here’s how it usually goes: look up something from their docs, be redirected to a doc about their “Pages router”, oops no I need “app router”, click on “app router” button, page does not exist. What the fuck
big_jerky-turky@reddit
Sounds like a you problem. The documentation is there
sickcodebruh420@reddit
Next.js middleware is infuriating and honestly baffling. I don’t think I’ve ever come across someone other than a Vercel employee claim that it’s good or reasonable in any way. It clearly exists in its current state to support Vercel’s serverless infrastructure.
I’m exhausted by Next.js. I was an early adopter of Server Components and Server Actions. We still have good things to say about Server Components; less good things to say about Server Actions. But Next.js itself has worn me down. Mystery crashes from its internals, an overly opinionated caching layer, a WIP build system, and new versions that add so many surprising new bugs and regressions that it’s hard to justify following their release schedule.
I’m not sure who the ideal Next.js user is anymore being “an organization that wants to go all-in on Vercel.” That ain’t us since we use containers. But so many orgs get burnt by Vercel that I can’t even tell who the ideal Vercel user is at this point.
I’m watching Tanstack Start very closely. Hoping to find a way to migrate when it’s ready. Moving away from Server Components will be challenging. Excited for everything that happens after that.
Dminik@reddit (OP)
Yeah the middleware is a constant source of frustration when making anything more complex than a brochure page.
What's even more frustrating is that when you decide enough is enough and eject using a custom server, you still can't do anything about these issues.
There's talk of a middleware rework on the issue tracker, but unless they scrap the whole thing and allow you to actually take over the request and do your things it's not going to be any better.
slvrsmth@reddit
Well good news then - as of Next.js 15.5 (mid-august), NodeJS middleware is considered stable. It's not ideal, but at least there should not be those WTF moments you describe. And yes, I also implemented logging before this got fixed :D
Dminik@reddit (OP)
Using Node.js middleware fixes the pino logging issue (sometimes) but it doesn't fix AsyncLocalStorage or that you can't pass anything except headers. Or that you can only have one middleware.
slvrsmth@reddit
AsyncLocalStorage - yeah, could not get it working.
One middleware only is true, but it only means you have to implement your own chaining / url filtering code. Something like https://medium.com/@0xTanzim/implementing-multiple-middleware-in-next-js-combining-nextauth-and-internationalization-28d5435d3187
bruisedandbroke@reddit
when vite came out I just sodded it off 😅 SSG thru Jekyll and CSR/dynamic through vite/react which has suited most things, and since it's transpiled to html it's practically infinitely scalable (a bad metric for pet projects anyway!).
too opinionated framework. react gives you the freedom to do what you want with vites HMR. want middleware? we got it! it's called express.js 😅
format71@reddit
First: it could be worse. It could be blazor… Second: I’ve always found remix/react router more sensible.
rk06@reddit
I am pretty sure, next, sveltekit, remix are all way better than next when it comes to this. the only surprising thing is how next can be this bad
BrownCarter@reddit
For middleware I use Hono in nextjs and it works fine. What I personally don't like with nextjs is sever actions and the way it handles error. Cause everything just returns a status code of 200 like wtf? I like the way sveltekit solved this problem.
TheRealRealRadu@reddit
Background: I have extensive experience in both NextJS and SvelteKit.
I don't see why, in 2025, one would start a new project using NextJS. The developer experience is abysmal, and the eternal argument of "large community, lots of tooling" does not really stand up anymore. Do engineers feel like they are or can be more productive in NextJS?
SvelteKit is better all-round, it is simple to understand, performs really well and, guess what, it can be hosted on Vercel if that's your poison.
Zoradesu@reddit
And honestly, if you're choosing to stick with React the tooling + libraries for React right now are extremely good that you don't need to reach for Next unless you have a really good use case for it.
Like as of 2025 most projects could probably get by with:
Personally, with how increasingly complex Next has become I think it's becoming harder and harder to justify picking it for a lot of people or startups, especially if you're building SaaS platforms.
abandonplanetearth@reddit
I am forced to use Next.js on projects with SEO requirements, and I have never hated a framework more than this one.
Next doesn't even let you access the Express request object.
That reason alone should convince any prospective developer to not use this framework, I have another dozen reasons locked and loaded for anyone still not sure.
dangerbird2@reddit
I kinda understand why they'd want to heavily discourage access to underlying request object, since they want to make Next cross-platform that can run SSR on alternate runtimes like Deno or cloudflare workers. But prohibiting access altogether is a completely baffling decision.
artemistica@reddit
I’ve tried next JS and found it infuriating, everything it does somehow is overly complicated… like adding in routing patterns to the file paths…. Why? Why reinvent the wheel, just use normal route based parameters. I’m sure a next JS dev will say that it’s somehow performant, Server side components rendering blah blah
But it ends up being an unmaintainable nightmare.
Now I just use vanilla React and Vite.js with Yarn. It’s simple, I can easily reason about and know what’s happening on the front end and I abstract as much complexity to my non JS backend to avoid that blight of a language when possible.
I’m hoping someday WASM is able to be a drop in replacement for everything JS is used for these days. It’s really fundamentally a broken language… for instance JS has asymmetric true tables. Insanity
beders@reddit
I was very confused by most of the article as I'm using Ring where the whole point is to have an open map to let your
middleware
do whatever thing you need besides the standard stuff.Pre-populate :foo with some data when /:foo/ is in the path, establish a request context for logging, auth/authz of various sorts, user role/permission checks etc.
Odd design choices by Next.js
Maybe-monad@reddit
You can mess up the routing and make it outfuriating in the process
lesterine817@reddit
All i can say is that it’s very very slow and dev and has carried on in prod. It’s just terrible.
Disclaimer: i don’t know much about nextjs since i just took over the project but for example, our redirect takes 10+ seconds to load that the user may think our application froze.
Kenny_log_n_s@reddit
That sounds like more of an issue with your project than next.js...
FINDarkside@reddit
The dev server being super slow is a very well known Nextjs issue though.
HappyZombies@reddit
My thoughts exactly, I means whats wrong with just using express? Works for every major projects I’ve done for 95% of my projects