Dark side of Next.js - App Router
Alex

Alex @asmyshlyaev177

About: Just another IT guy, 5+ years of coding on Frontend, Follow me on GitHub , appreciate it.

Location:
void 0
Joined:
Jun 27, 2019

Dark side of Next.js - App Router

Publish Date: Nov 6 '24
66 26

Today, I want to share the disappointing issue with Next.js - App router.

About SSR

I assume that you're aware of what SSR is and vaguely understand how it works.
E.g. server return HTML page with markup, while JS and CSS bundles downloading, user see the page instantly and parsing JS code taking some time.

The _rsc problem

Every time you switch route in Next.js, it's requesting some meta info from server first, you can see such requests as {smt}_rsc, stand for _ReactServerComponent as I can guess.

_rsc requests

Server responds with something like this

_rsc response

Problem that Next.js router make those requests even if you need to update searchParams, e.g. /url?param=value, it isn't a new page, all purely client side, but there is still a _rsc request.

Another example, when have list with cards, every card has an edit button with Next/Link component, and separate edit page like /card/{some_id}/edit.
Next.js trying to optimize things and prefetching those _rsc requests ahead of time. In result, there will be a request for every card, but user possibly won't ever click an edit button.

Even if you have very fast server and internet connection, network requests making UI slower, and put more stress on a server.

While SSR is great for an initial page load, navigation after app loaded happens way more often.

Discussions

There are few discussions about this problem:

How to solve it

Switching to something like Remix will be too hard for existing project.

Can use plain old window.history interface with pushState/replaceState instead of App router, when you sure it purely client side.

For queryParams/searchParams can use a library to simplify those things - state-in-url , it's using history by default and has an option to use App router. Also, it's way simpler than NUQS, parsing with proper type just work out of the box.

Tnx for reading, consider giving it a like and maybe share.

Comments 26 total

  • Boopathi
    BoopathiNov 6, 2024

    This is a great analysis of the App Router's _rsc requests! It's frustrating how they impact performance even for client-side changes. The solution using state-in-url is interesting; I'll have to look into that!

    • Alex
      AlexNov 7, 2024

      Next.js moved fast in order to gain popularity, e.g. use canary versions in production, and they just wrapped old pages router and how App router works.
      Hard to support 2 different mechanisms, and make both of them work good.

      Sad that need to come back to window.history API. Recently finished task when those _rsc requests made UI slow.

  • Shifa Ur Rehman
    Shifa Ur RehmanNov 7, 2024

    If you dont want that feature, making a new Link component with prefetch false would be enough rumble for you. Everything is customisable, if you wish to. Sure some things are opt-in and some are opt-out, but there is nothing dark about it.

    I didnt like the caching system next had, so for a long time i abstracted fetch to not have cache by default.

    This prefetch behavior is not app router specific, its present in pages router as well. Because it has nothing to do with pages or app router, its a feature of the Link component.

    • Ismatillo
      IsmatilloNov 8, 2024

      And actually it's very useful to use prefetching if you can handle it correctly

    • Alex
      AlexNov 8, 2024

      I expect that Link and Router can see that only changing queryParams doesn't require fetching anything. It's pretty easy to implement.
      Pathname related to a directory and page.tsx, but queryParams doesn't related to anything.

      • Shifa Ur Rehman
        Shifa Ur RehmanNov 8, 2024

        I don’t get what you are trying to say :/ can you please elaborate a little? Do you want the prefetch to happen/not happen at queryParams level and not on page level or vice versa?

        • Alex
          AlexNov 8, 2024

          I mean queryParams shouldn't trigger a prefetch by default, it would be better.

          • Shifa Ur Rehman
            Shifa Ur RehmanNov 8, 2024

            This is the beauty of it. You can opt-out of it no problem and use prefetch explicitly or keep prefetch as default and disable it whenever you require optimisation. Its not a bad thing, its just a non-conventional way of doing it. That however is debatable yes.

            • Alex
              AlexNov 8, 2024

              For absolute majority of cases their approach isn't right, should be sane defaults.

              • Shifa Ur Rehman
                Shifa Ur RehmanNov 8, 2024

                Yeah I know but that’s where “opinionated” part comes in. Just that their opinion isn’t liked by majority of people. And they are fixing it. Like with cache. But to think or say that next isn’t production ready, or saying that next is cycling its canary to production too quick is absolutely disgraceful. For a reference their turbo team waited 18 months for their tests to pass before it made to devmode, still not in production.

                The amount of care and developer opinion regard next has is insane. Lee himself acts more like a mentor and teacher than vp of a highly successful frontend framework. The ideas that he brings into his streams are not nextjs specific, instead it spans over the design principles of how web frameworks work and should work in general.

                I suggest you turn back on this statement of yours, it’ll do no one good. Because if you want everything made catered to your desires and needs, why not make a framework yourself and bring on open source support into it?

                I intent absolutely no offence by anything what I said. Everything i said is my opinion and analysis of the current js landscape in reference to nextjs.

                • Alex
                  AlexNov 9, 2024

                  If anybody make any product is totally fine to give feedback or criticize it, that how they can improve. Because they won't do a thing unless enough people complain about it, and it is a sane approach.

                  Having 1 popular library myself, I'm doing the same. And I struggle that not enough people giving feedback and opening issues. Companies paying money to do research into what customers want, I was contacted recently by Vercel employee, and he asked me about pain points in Next.js.

                  Being polite and silent doing only harm.

                  People who can't handle feedback and critic can't improve, so can't create anything good enough. I never wrote any good code from first try myself, need 2–3 iterations at least.
                  Discussing things is helpful, few good points here in comments, few ways to deal with the issue.

                  And yes, they moved too fast with canary releases, luckily, React itself is rock solid.
                  If majority of people won't like their opinion they can switch to other framework, do you think Next.js team want that? For example Cypress ignored feedback for years, and now many people just switching to Playwright, including myself.

                  I wonder where you got such counterproductive attitude. Why you worry about offending anybody, you're grown up (I assume at least).

                  • Shifa Ur Rehman
                    Shifa Ur RehmanNov 9, 2024

                    Fair enough. I would consider this discussion concluded then.

    • Omri Suleiman
      Omri SuleimanNov 8, 2024

      I learnt something very useful! thank you <3

  • J.R. Hill
    J.R. HillNov 8, 2024

    I agree that many tiny requests will lag the UI for a single user, and also result in more activity the server must respond to.

    ...navigation after app loaded happens way more often.

    I don't think this has to be the case. My recommendation in situations like this, when possible, is to architect the user experience in such a way that it doesn't require a lot of route changes. In other words, look for ways to streamline the experience, rather than take a complex experience and try to force it to work with a complex technical solution.

    This kind of incentive is actually pretty valuable. If your user experience is not simplifying whatever needs to be accomplished, this is a product/quality issue. You should be taking whatever is complex about the problem you're solving for the end user and presenting a simpler and easier to use interface to it. When we find that we are adding complexity, or even exposing the exact same amount of complexity as the underlying problem, we are not really adding any kind of value to the user aside from surface level aesthetics.

    • Alex
      AlexNov 8, 2024

      Minimize route changes is a good idea.
      Often got the code that somebody else "designed".

      With react-router there weren't such problems, navigation is instant.

  • Mordechai Meisels
    Mordechai MeiselsNov 8, 2024

    Using window.history isn't a workaround or some kind of hack, it has first class support tightly integrating with the app router state.

    It's the official way of doing client side navigations where you don't need to fetch server data.

    • Alex
      AlexNov 8, 2024

      Yeah, but when framework has a router I expect it to work in all situations, need some effort to think when to use what, and window.history less user friendly.

      • Samuel Boczek
        Samuel BoczekNov 8, 2024

        You are just seeing how browsers work, not Next.js limitation.

        • Alex
          AlexNov 8, 2024

          It's ridiculous.
          Open dev console, put window.history.pushState(null, '', '?key=value') and see no network requests, it's not browser.

          • Mordechai Meisels
            Mordechai MeiselsNov 13, 2024

            You have no damn understanding of how Next.js works. In fact, navigation with the Pages router work identically, every push loads the result of getStaticProps()/getServerSideProps() unless you explicitly opt into Shallow routing.

            Next.js isn't an SPA that loads all pages at once and uses only client side routing. Next is fully code splitted, where every page only loads its essential data. Next is highly optimized to load a minimal diff on page load, not the entire react tree.
            It also prefetches the data when possible to speed up navigations even faster.

            On the app router, every page can load its own data using Server Components, you don't want to miss out those loads when routing. Changes to the search params are accessible via the searchParams prop in the server component, you can load different data when it changes, such a table pagination.

            Shallow routing is still perfectly supported, by using the native browser History API all while magically keeping usePathname() and useSearchParams() in sync.

            The choice of the nextjs team to use the browser API instead of passing a shallow option is perhaps to allow you to use 3rd party JavaScript libraries that deal with the History API and are completely agnostic of Next.js

            • Alex
              AlexNov 13, 2024

              I get used to SPA times, when if I'm using some tool it solves all or almost all use cases.
              Can't remember case when I have to use history api with react-router for example.
              Here recommended approach backfire pretty often.
              It's just confusing, sure that not only for me.

  • Rense Bakker
    Rense BakkerNov 8, 2024

    If the inputs for the server component change it has to render on the server yes... If you don't want this behaviour, put use client at the top of your component.

  • martin rojas
    martin rojasNov 9, 2024

    This goes to the heart of developers and using NextJS. As a developer you want to control everything and understand what is going on. However NextJS provides a lot of optimizations that only enterprises ever get around to implement and are overkill when starting a new project or running a small site.

    Adding them on later always costs a lot of developers time and effort so I understand that having the framework is better, but it bugs me as a developer to have things I don't control.

  • Gaurav Patel
    Gaurav PatelNov 12, 2024

    Learn about prefetch props in next js

    • Alex
      AlexNov 12, 2024

      It's not about prefetch, it's about that often enough need only client side navigation, without fetching anything.

  • sewiko
    sewikoNov 12, 2024

    nice article

Add comment