Comment by solatic

1 month ago

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.

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

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.

  • Vercel funds and sponsors many open source projects that would otherwise be struggling for funding. Their framework is tailored to the platform they build because that’s a good experience. I don’t currently use them, but people get funneled to their paid plans because it’s a good developer experience. I acknowledge that they are a capitalist enterprise with their own motives, but I think cancer of the modern web is a little strong.

    • People get funneled to their paid plans out of necessity. While NextJS is open source, the back-end to run it is not. That is where all the complexity lies. Even on Netlify, you run into crazy issues with things like their image stack. It does all this "Optimization" and caching that make it completely impossible to reason about and you run into implementation problems from the providers. Sure you can just run it in a container but then you are taking on all the complexity of NextJS preoptimizations without getting any of them.

      Serverless framework attempted to make this stack to run yourself for Next but it is buggy due to the complexity of Next. Open source includes being able to run it. Releasing the framework and funding OSS that also enhances NextJS is nice, but it is a trap because if it comes time to seriously run it, your only option is vercel.

    • Vercel won the techfluencer space like none other. They get a bad rep largely due to the influencer crowd adjacent to them. Influencers are cancer but an almost necessary one like marketing.

      Annoying, obnoxious, and always trying to get your email but god damn do they get your attention.

      2 replies →

    • I agree, I don't understand the hate in this thread.

      And I think their paid hosting was actually really good, up until they switched their $20/month plan to a whatever-it-may-cost and we-send-you-10-cryptic-emails-about-your-usage-every-month plan. That's when they lost me, not because it got more expensive but because it became intransparent and unpredictable and annoying instead of carefree.

And even if you fall under the first category, I find it hard to believe that the performance bottleneck is solved by using Vercel and SSR.

With all the other crazy shit people are doing (multi-megabyte bundle sizes, slow API calls with dozens of round-trips to the DB, etc) doing the basics of profiling, optimizing, simplifying seems like it'd get you much further than changing to a more complex architecture.

> 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.

  • Notice that nearly everyone pushing edge-execution JS has some infrastructure to sell you.

    It's positioned as a ramp up for companies where frontend and backend devs work at loggerheads and the e-commerce / product teams need some escape hatch to build their own stateless backend functions

  • > 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.

    In what way has that been a boon? Context switching between languages, especially PHP, seems like an even bigger headache. Is it strlen($var) or var.length or mb_strlen($var)?

    Do you ever output JavaScript from PHP?

    My biggest question though is how do you avoid ever duplicating logic between js and PHP? Validation logic, especially, but business logic leaks between the two, I've found. Doing it all in Next saves me from that particular problem.

    • spoken like a middle manager.

      why would anyone send JavaScript from the php? why care about duplicating a couple json translations and null checks... it's all code is today anyway.

      and switching languages? you can't use most of js as it is. even something as simple as split() have so many weird bugs that everyone just code from a utils lib anyway.

      1 reply →

  • I am a backend dev, and I needed a website that was temporary for an event. I thought to myself this would be a good opportunity to learn some frontend development.

    After looking through the 20 different popular front end frameworks and getting confused by SSR, CSR, etc. I decided to use Nuxt. I thought oh this is great, Vue makes a lot of sense to me and this seems like it makes it easer to make Vue apps. I could not have been more wrong. I integrated it with Supabase + Vercel and I had so many random issues I almost scrapped the entire thing to just build it with squarespace.

Yeah this is basically it. Vercel is trying to solve for optimised performance by using a combination of React Server Components, Partial Pre-rendering, Edge servers, streaming, etc. A lot of their seemingly weird design and API decisions basically come down to that. If you need it, it's good that it exists. But you can also go pretty far with doing some ssr in an edge function too.

> 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.

  • Having front-end and backend in the same language and mono repo is such an outrageous productivity booster for me. Obviously the opposite may still be true if you've got big, separate frontend and backend teams but if you just want to ship.. I wouldn't have it any other way.

    • Full-stack rich schemas, not the poor lossy JSON Schema or other language-agnostic ones, are so nice for long-term quality and development velocity. You get to categorically avoid bugs that drag teams down. Zod 4, ArkType, and Valibot are all great.

      2 replies →

    • You can have a monorepo with any tech stack you'd like.

      You can write your front-end and back-end in the same language.

      No shade to you for finding a productive setup, but Next.js tightly couples your front-end and back-end, no question.

      2 replies →

  • I don't agree. Having front-end and backend in the same language is so convenient I would never go back to doing it the old way. I'd rather compile the frontend to WASM than introduce a mismatch.

    I used to use Django and there were so many issues that arose from having to duplicate everything in JS and Python.

  • Agreed. It's a bit insane that updating a button padding redeploys your entire backend.

    • Not the same problem though is it? You can have a express backend and react-vite frontend both in typescript and in a mono repo.

  • or dont even write a SPA. Send hypermedia from your backend language/framework, use HTMX + Alpine or Datastar, and call it a day.

> 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.

  • Does it? Just look for "use client" at the top of the file.

    • I love this comment!

      "use client" does NOT mean it only renders on the client! The initial render still happens on the server. Additionally, all imports and child components inherit the "use client" directive even when it's not explicitly added in those files. So you definitely cannot just look for "use client".

      See what I mean now?

      From the docs:

      ```

      On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks, by individual route segments (layouts and pages):

      Server Components are rendered into a special data format called the React Server Component Payload (RSC Payload).

      Client Components and the RSC Payload are used to prerender HTML.

      ```

      HUH?

      ```

      On the client (first load) Then, on the client:

      HTML is used to immediately show a fast non-interactive preview of the route to the user. RSC Payload is used to reconcile the Client and Server Component trees.

      ```

      HUH? What does it mean to reconcile the Client and Server Component trees? How does that affect how I write code or structure my app? No clue.

      ```

      Subsequent Navigations On subsequent navigations:

      The RSC Payload is prefetched and cached for instant navigation. Client Components are rendered entirely on the client, without the server-rendered HTML.

      ```

      Ok...something something initial page load is (kind of?) rendered on the server, then some reconciliation (?) happens, then after that it's client rendered...except it's not it actually does prefetching and caching under the hood - surprise.

      It's insanely hard to figure out and keep track of what is happening when, and on what machine it's actually happening on.

      1 reply →

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.

> 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?

> 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.

  • This has nothing to do with multithreading, though?

    • Absolutely correct. Those are runtime execution context-issues. There are other frameworks that do force you do deal with those (and in other languages, probably), but I believe in next.js the difficulies are at another level - because of poor documentation and the built in abstractions to allow for running next.js both in development, node.js server, and edge.

    • Not OP but wasn't the article about lots of async/await context issues?

      If the handle() method of the middleware API would have provided, say, a context.Context parameter, most of the described debugging issues would have been gone, no?

      1 reply →