Next.js: Use with React Router 4

Created on 5 Apr 2017  ·  122Comments  ·  Source: vercel/next.js

Is it possible to use next.js with the new react router v4?

Most helpful comment

@timneutkens adding react router integration would help increase nextjs adoption and make development better. Devs like myself would love to see this happen, please consider increasing the priority.

All 122 comments

@Knaackee Did you try out the possibility? I am wondering as well if someone has gotten it to work with any version of RR?

Next has his own router, why use RR?

@sergiodxa Weighing options as I port my existing app to Next. I have a static, nested route config working and wondering what can I keep using, and what not..

@oyeanuj 🤔 you can gradually migrate to Next, just set Next.js to handle 1 route and use a proxy to have both your current app and the Next.js one, then move a second route from RR to Next.js, and that way you can keep your current app while migrating, eventually you will have everything in Next.js

From looking at the examples it seems that next has a single route table like RRv2-3 and does not support "nested routes" like RRv4. These are nice.

I would try to use RR or is there a big caveat i don't know about?

@igl Have you figured out a solution to that?

The new react-router 4 paradigm of nested routes is a game-changer, and is something of a must-have in our current project. I'm wondering if anyone has succeeded in getting rr4 to work with next.js?

MemoryRouter does work, if not as intended...
Otherwise, dynamic components can be client-side only, where HashRouter works fine...

const AdminPage = dynamic(
  import('..../AdminPage'),
  { ssr: false }
);

I 'm also following @malixsys approach and handling client side routing with react-router and all the server rendered content with next router.

@malixsys @pegiadise can u please give some more details how to use next router and react-router together ?

You can set a flag in componentDidMount and conditionally render the <Router /> when the flag is truthy. (componentDidMount does not run on server 😉)

In fact, we're incorporating React Router inside Next.js soon :)
https://twitter.com/rauchg/status/948318111828099072

Is this still happening? I can see the release notes for V6 canary and there is no mention of it.

Eventually. It's definitely on our minds. We've got other priorities right now (layout component, reliable development and a few other long standing open issues).

That is a shame, it might be low priority for the team but it's basically the only thing stopping people like me from starting to use it. I read your tutorial until I got to the bit where it said that routes have to be set up twice then gave up.

@timneutkens adding react router integration would help increase nextjs adoption and make development better. Devs like myself would love to see this happen, please consider increasing the priority.

That is a shame, it might be low priority for the team but it's basically the only thing stopping people like me from starting to use it.

Same.

Can we at least re-open this issue so it can be tracked?

I'm going to reopen this, but note that this is an open source project and we don't have a very strong case for it at this moment for zeit.co, since we use Next.js for everything.

This is why I was saying it's part of the longer term goals and can't be implemented immediately, but we're working towards it.

The features I've been introducing in Next 6 are actually working towards React Router support.

We had other priorities for Next 6, which are tremendously improving Next.js's reliability and scalability, for example 100x faster page resolving, App Component, making next export work in development, babel 7, etc.

I hope this elaborates on my earlier comment.

So the TLDR is:

  • We're going to do it, but not immediately
  • Next 6 has many improvements to different parts of Next.js

To further extend @timneutkens's comment: we definitely want RR, but we don't have any pressing limitations in the current Router that make it a priority. All the routing use-cases you can imagine have been implemented successfully with the current Next.js API

There are two reasons we really want React Router support for:

  • Simplify our own Next.js codebase, not have to maintain our own router, make things smaller and modular
  • Simplify the migration path of large applications already using RR

As such, I agree we should keep this issue open!

As a counterpoint, not having react-router means that next works nicely with relay-modern and was one of the reasons we switched to next from our old react-router app.

@merrywhether I worked on an RRv4 app with relay-modern last year. Care to be more specific?
I don't remember us having serious issues because of either.

@igl This is according to relay's documentation: https://facebook.github.io/relay/docs/en/routing.html#react-router-https-reacttrainingcom-react-router

The problem is that RRv4's component approach doesn't allow for determinism during the pre-compilation step, which can result in request waterfalls in the client.

@rauchg Out of interest, my understanding of Next's router is that it doesn't support the concept of nested routing, so you can keep outer markup while navigating within a page. Do you know if there is a way to make this possible with the current router?

@dbbk check our nextgram example app (https://github.com/now-examples/nextgram), it does exactly that

In next 5, we're accomplishing "outer markup" by having top-level layout components that all of our pages extend: base layout has top nav, then a few sub-layouts that extend base for lists/details/etc, and then our pages components extend these sub-layouts with their own specific content. In next 6, you could also accomplish basic "outer markup" using _app.js I believe.

Will the next version be configurable to choose a routing solution that is not React Router?

Hi, i only need react router in order to pass props to pages (using <Route render ={} /> instead of <Route component ={} /> ), can i do it with Next?

From looking at the examples it seems that next has a single route table like RRv2-3 and does not support "nested routes" like RRv4. These are nice.

Hi,

Does this mean I have to create a single page for a single route?

Let say if I have 2 routes sign up, log in. I would have 1 page that shares the same layout, the only difference is area of forms. That is I just need to create 1 file in pages folder. But with next routes I have to create 2 files in pages folder. Is it?

If it is, then the layout is is remounted with every navigation, not just forms area, right?

@7c78 One thing you can do is leverage _app.js for persistent page layout for all pages. The other thing to do is to create shared layout components that you can reuse throughout various pages in order to achieve what you are looking for:

// pages/login.js

class LoginPage extends React.Component {
  render() {
    return (
      <AuthForm>    // same component can be reused in signup
        <form>
          ...implementation of login
        </form>
      </AuthForm>
    );
  }
}

Additionally, you can do what we've done recently and define base layout components that your page components all extend:

//layouts/baseAuth.js

class BaseAuth extends React.Component {
  abstract formContent();  // we use typescript, but you can have the same concepts
  abstract formSubmit():

  render() {
    return (
      <SomeStyledDiv>
        <form>
          {this.formContent()}
          {this.formSubmit()}
        </form>
      </SomeStyledDiv>
    );
  }
}

And then you just extend BaseAuth in your login and signup pages and define formContent and formSubmit in each of them (these are toy examples, since I don't know you exact requirements).

@merrywhether
I currently use your approach, and next examples use it too.

But my concern is I need to create separate pages for separate forms. That is layout is reused but not page. And the layout is is remounted with every navigation.

With RRv4, we have single page and forms are rendered/remounted based on routes (not the whole page). Routes are just components.

Thank for fast response!

@7c78 That's true about remounting, though I do think the DOM nodes are re-used as the vDOM resolves to the same state.

It's not something we've been super concerned with because we also can't use react-router with relay-modern, so we've had to use this pattern regardless.

@merrywhether I am not sure about vDOM because server returns new document/html for every routes. Sorry, ignore this assumption, I am just a newbie.

I agree that we have to use this pattern anyway. Thanks!

You can use RR with next.js by having your whole app be in the pages/index.js but you lose some of the goodies of next like out of the box code splitting and have to set that up yourself.

I would love it if Reach Router was considered. It's very similar to react-router and brings some important benefits:

  • It solves some important a11y concerns around link generation and focus management (https://reach.tech/router/accessibility).
  • It weighs less (at the time of writing)

Reach Router is also great 🥇

RR-style dynamic routes are a nice API, but static (and statically analysable) routing brings a lot of benefits too. Neither approach is a slam-dunk winner.

@sorokinvj That's only supported via a plugin (currently) .. https://github.com/fridays/next-routes

static links are so basic that it doesn’t even support parameters in links...

i am using a third party package next-routes for now https://github.com/fridays/next-routes to get around it

Sent from my iPhone

On 24 Oct 2018, at 23:01, Andy Ingram notifications@github.com wrote:

RR-style dynamic routes are a nice API, but static (and statically analysable) routing brings a lot of benefits too. Neither approach is a slam-dunk winner.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.

We're using next-routes as well for the time-being, but I believe the next team is working on adding path parameters to their file-system routing via regex file names (inspired by Sapper).

@merrywhether I'm using next-routes as well but would prefer this be part of Next.js core.

You mentioned

I believe the next team is working on adding path parameters...

I'm curious do you have any reference for this? Perhaps an open issue for route parameters? I'm not able to find one... Perhaps the plugin solves the need and that will be the recommended solution going forward.

@curran The source was a tweet from on of the sapper.js devs, saying that next was taking inspiration from sapper.js and implementing regex-filename-routing in a future version. Of course, Twitter being what it is, I could not for the life of me find the original tweet.

This issue was raised on Apr 5, 2017 and now is Feb 27, 2019. Almost 2 years and no solution
May be its time to replace half-assed built-in router with something good?

Ouch. That's quite insulting to NextJS devs who put many hours into the routing solution.

I missed ReactRouter at first. Now I don't even remember NextJS has a different Router until someone reminds me. Verbose Link API is trivial to wrap with proxies (depending on your data/API architecture), for example. Sharing this top secret: 😆

import _Link from "next/link"
export function Link({as, children, href}) {
  as = as || QS.parse(U.parse(href).query || "").url || null // QS, U are parsing libs
  return <_Link as={as} href={href}>
    {children}
  </_Link>
}
<Link as="/about" href="/page?url=/about"/> verbose
→
<Link href="/page?url=/about"/> ok

I think we all should spend less time complaining about secondary stuff 😉

@ivan-kleshnin Nice i added a similar wrapper

As per previous comment I'd like to point to https://www.contributor-covenant.org/version/1/4/code-of-conduct

I've hidden said comment.

I have no problem with next/router for most of use cases.
But it should improve a bit on the universal routing part.
In case of Now 2 deployment, i'd love to just take now.json and use it to route in my application.

If you want to implement RR4 into nextJs project, you need to do 2 things:

  1. Prevent NextJS SSR, By using next/dynamic you can do that.
  2. Using HashRouter instead of BrowserRouter -> if user reload page, the browser can load the previous page (not 404 page)

If you want to implement RR4 into nextJs project, you need to do 2 things:

  1. Prevent NextJS SSR, By using next/dynamic you can do that.
  2. Using HashRouter instead of BrowserRouter -> if user reload page, the browser can load the previous page (not 404 page)

Thanks for this reply, helped me a lot.

@reach/router and react-router 5 are merging: https://reacttraining.com/blog/reach-react-router-future/

How does this affect next.js?

@alp82 Since Next.js still doesn't use React Router or Reach Router it will not affect Next.js at all.

i need switch routes functionality in nextjs for rendering multiple pages components in index pages.
so how can i implement this in nextjs.......???

If you want to implement RR4 into nextJs project, you need to do 2 things:

  1. Prevent NextJS SSR, By using next/dynamic you can do that.
  2. Using HashRouter instead of BrowserRouter -> if user reload page, the browser can load the previous page (not 404 page)

if you want to re-render your previous page without throw 404 error so just used this get route in your express server file.

server.get('your params', (req, res) => {
const actualPage = '/your_page'
const queryParams = { id: req.params.id }
app.render(req, res, actualPage, queryParams)
})

I documented an approach to use next.js with react-router, providing a single entry point file instead of native file system-based routing and fully preserving native SSR features.

I'll be happy to receive feedbacks and improve what I did.

The documentation is available as:

Cheers!

I would highly discourage including react-router that way as you end up with a single entrypoint, which means (tremendously) slower development builds, higher chance of shipping too much code to the client-side and less visibility into optimizations like automatic static exporting.

@timneutkens Maybe i'm wrong. But with lazy loading, the routing config is just one config file. I don't see it will affect scalability or performance here. I'd love to learn more on this.
The benefit of react-router is devs have total control on the code.

@timneutkens, I won't start an argument here but I'd kindly ask you to un-hide my comment. I spent time to make my job available and give it back to the community and I don't see how silencing people could help open source development.

@timneutkens as for the points you mention it's a matter a trade-offs. Mine is an experiment to sound how Next.js could be used with a different setup.

Too much code on client-side

Any modern bundle can split client assets in chunks and react-router routes are actually very convenient splitting points.

Higher dev build times

It's a price to pay for big project, but nothing not addressable with some proper webpack fine tuning.

No static exports

I agree static exports are an important optimisation layer. Most of the pages served by an average Next.js application have to retrieve dynamic data anyway and cannot benefit of static exports.

There is no lack of solution about this concern. Eg. it might still possible to manually declare a list of routes to be statically exported

The reason I hid the comment is that this is a high traffic issue and it does not reflect our recommendation for building Next.js apps. If someone ends up here looking to use react-router they'd end up blindly using your example and not investigating how to properly set up routing using Next.js.

It's a price to pay for big project, but nothing not addressable with some proper webpack fine tuning.

You can't speed up dev-time bootup based on your approach, there is no specific fine-tuning of webpack configuration as webpack will just compile and watch every single route that you import which massively slows down edits to common components. Hence why Next.js has on-demand-entries: https://nextjs.org/blog/next-8#improved-on-demand-entries

Furthermore there is (automatic) prefetching of routes etc. There's tons of specifics I could go into here, but the tldr is that you'll end up with a worse developer experience and app.

I don't mind un-hiding the comment if it properly reflects that the only time you want to use it is to migrate an app that is already using react-router and then gradually move to multiple pages.

Hey @timneutkens
Would you count some of pros that being statically analysable brings to the table and aren't possible with the dynamic routing solutions?

Ive read all the comments and still not clear if RR4+ will be included or optional in future iteration of next.js. Is the a router roadmap or something similar?

@laurencefass it seems there is no plan to support react-router (as of today).

To me, the routing system of Next.js is becoming mature enough so we probably don't need it (anymore) anyway :)

"To me, the routing system of Next.js is becoming mature enough so we probably don't need it (anymore) anyway :)"

Except for those seeking to incrementally adopt Next.js in an existing codebase. I think the more useful discussion is probably not "Next.js routing vs react-router routing". I think the more useful discussion is "how can I migrate a huge app using react-router to Next.js, incrementally?"

Next’s router doesn’t have the ability to nest route views though, does it? Every navigation to a route blows away the DOM and refreshes it. Nested views are a pretty common requirement.

@dbbk I heard that nextjs team is working on it.

next js is pretty flexible with routers. https://dev.to/toomuchdesign/next-js-react-router-2kl8

I'm moving a website from normal JS and jQuery codes to React. Unlike the old codes, I need to prevent the music from stopping when changing page, so I used React Router for that.

Now for SEO purpose, because I have some good traffics from Google Search, I need to maintain that. So I would prefer SSR with Next.js for better performance.

Is Next.js is able to render a page on server side and then once page loads in Client side, Next.js would let the navigation under React Router control, so that if User is listening to music, the Next.js Link won't have to leave the current page to stop the music?

O can Next.js makes Client-Side routing only?

If integrating React Router will be able to resolve this, then I'm in. Because Continuous Music Playing is a Must for me once the App reaches the Client Side.

next js is pretty flexible with routers. https://dev.to/toomuchdesign/next-js-react-router-2kl8

@laurencefass , that's a very good approach, I read it before. And the article say that Next.js team does not recommend it, don't know why. But it seems good to me

@KeitelDOG you do not need react-router for that, Next.js routing will bring you the same benefits, plus your app will be lighter thanks to automatic code splitting (that you would not have easily with react-router)

_edit: I will just add this: perhaps the only advantage of react-router are the easy nested routes in the same view feature, Next.js router should solve 95% of your usecases_

@martpie Thanks for the response, that's what I saw yesterday night with the Link component. Then Next.js is the mix Server-Client that I wanted.

And for a component controlling granularly its own nested routes dynamically, I really like it with React Router. But I'm pretty sure I can get a work around, because I'm not changing a React website to Next.js, but instead planning and testing to change a JS - jQuery website to a React multi pages application without loosing my SEO advantages on Google. So I think I should go with Next.js

@timneutkens any plans to support this in Next.js 10?

@TrejGun thanks, that is definitely not off topic.

Have any plan?
The next/router is great, it provides a lot of help. But we need more professional router to cope with complex applications. React-router is a leader in router.
Maybe can refer to after.js.

Yeah, this page based system is simply not sophisticated enough to handle complex data driven applications that could benefit from nested routes.

React-router is about to launch v6 version, which will be the best router to date. I am looking forward to next.js suppor it.

A better approach is to separate next.js and router, allowing people to choose their favorite router freely.

+1 for previous comment. next.js is amazing the only reason i am not using it is the lack of flexibility on Router. Please support React Router 6 in future releases or make router swappable.

People really keen on React Router might be interested in following the new project ”Remix”, it's a Next.js alternative that uses React Router, by the same creators:

I think the problem is the framework is deeply tied to that router because of SSR, Server Side Props etc....

Next is built with performance in mind, and server-side react-router has a major performance implication in that you must walk the DOM tree before you know what you will try to render, and thus what data you will need. The entire purpose of getInitialProps is so that you don't have to do a throwaway render of react before fetching data, a common pitfall that lots of frameworks experience on the server (and in the client, where it manifests as request waterfalls). Next could potentially get around this by having each top-level page declare _all_ of the various data patterns it's various sub-components might need and branch on the full request path (or do a massive single overfetch), but this would get unwieldy quickly and wouldn't actually be that different from declaring each page individually.

This is the same reason that Relay is not compatible with react-router either, and you can't accuse facebook.com of not being a complex website.

The main successful strategy for working with the Next router is leaning into composability (which is the driving trend in modern React anyway), allowing you to re-use components without major duplication while also having efficient SSR that is able to fetch all of its data (via getInitialProps) before ever talking to the React renderer.

I feel as though the performance penalty of walking the tree is overstated. Many production applications today are doing this with eg Apollo and it appears to be just fine.

Plus you can also CDN cache your responses if you really want to relieve the server of doing too much work.

Sure, I'm just pointing out the primary reasoning behind why react-router is (AFAICT) fundamentally incompatible with Next in its current implementation. Lots of sites don't really need perf at all, as evidenced by people happily using free Heroku dynos with slow cold-start times (and I want to emphasize I don't say this condescendingly as I do this for some sites too and it can be the perfect fit). But Next wouldn't be popular with some of the larger companies using it if it were less aggressive about performance as those companies would care about their server response times being measurably slower. If it weren't a concern for some sites, people wouldn't use (and eagerly await improvements to) React's streaming renderer to start responding before even a single render has completed, let alone two.

You definitely can CDN cache your responses, but that eliminates a lot of personalization/login options (as it is a trade-off with how low you want to drive your hit-rate or defer partial page rendering to the client). If you can CDN cache your whole app, you might be better off using CRA and react-snapshot and avoiding servers entirely. It's not necessarily a question of how much work your server is doing but rather how long it takes to respond to a request.

And Apollo is a great example of a framework that emphasizes ease-of-use over performance, compared to a more opinionated/perf-oriented framework like Relay. It's all a spectrum.

Yeah, I guess that's fair enough. But I'm curious to see how remix.run turns out, maybe they will come up with a novel approach to make it work with react-router. Yeah it's true that nested routes aren't compulsory, but surely you must agree that it is more intuitive to have bits of the inner UI change with the route, than to have different pages and wrap each of those pages with differing layouts.

As of next 9.3, there's getStaticPaths in addition to getServerSideProps to help the framework discover paths to pre-render when the path has route parameters. Maybe a similar approach could be taken with react-router.

@merryweather: "Next is built with performance in mind, and server-side react-router has a major performance implication in that you must walk the DOM tree before you know what you will try to render"

Naive question: Can you just render top level links and fetch/prefetch/cache once code running on the client. If you dont know where the client will navigate does it make sense to traverse DOM tree on the server?

Naive working scenario: when the client requests a URL just render top level links and default active link content and ajax/fetch everything else on request (or prefetch in the background once once the page is loaded)... everything else includes all lower level routes... rinse and repeat... ?

@laurencefass but even the top level links are in code and have to be discovered right? Or do you mean to use file-system routing alongside react-router so that the top level links are discoverable?

@avin-kavish Im not the best person to answer details on implementation but on the client only needs to render the initial screen contents: top level links + default content. Anything else is redundant on first load I think. So why walk the DOM on the server?

Main issue with Next.js is not the router, it's the data fetching pattern with getInitialProps, getServerProps or getStaticProps. Why ? Because it breaks the data-isolation for component that needs it. For example, you want to get data for the menu, where will you fetch it from ? I don't know. Top components like pages shouldn't know anything about it, right ?

Main issue with Next.js is not the router, it's the data fetching pattern with getInitialProps, getServerProps or getStaticProps. Why ? Because it breaks the data-isolation for component that needs it. For example, you want to get data for the menu, where will you fetch it from ? I don't know. Top components like pages shouldn't know anything about it, right ?

Would you elaborate please. And what is the alternative solution?

@lishine I'm sorry for a bit off-topic here, but in most case i don't see Router is the main issue here. Next.js router is good, declarative, convention over configuration is good. The only thing that i can't use in Next.js is the data fetching methods like getInitialProps,...
In my apps, each component will need to declare its own data right in the same place, in the same file, whatever it's graphql or rest.
Top pages component is just for composing child components, and fetching data is not its job. Child component must get data of itself, not its parents.

Here's my sample of code that i'm using for my app for clarity:

const query = `
{
  result:users(
    where:{
      _and:[{
        active:{
          _eq:true
        }
      }, {
        is_exam_manager:{
          _eq:true
        }
      }]
    },
    order_by:{
      created_at:desc_nulls_last
    }
  ){
    id
    key:id
    user_code
    first_name
    last_name
    password
    active
  }
}
`
const Main = (props: any) => {
  const {
    data: { result }
  } = props
  return (
    <div>
      <Add title={'Add user'} role={'exam_manager'} />
      <Table
        columns={columns}
        dataSource={result}
        bordered={true}
        size={'small'}
      />
    </div>
  )
}
const MainWithData = graphql(query)(Main)
export default MainWithData

As you see, you have one component with its own data. You can put it anywhere you want.

Of course, you can use Next.js pattern without any problem, but in my case, i prefer isolation for data and component as much as possible for easier maintainance and refactoring later.

In my apps, each component will need to declare its own data right in the same place, in the same file, whatever it's graphql or rest.
Top pages component is just for composing child components, and fetching data is not its job. Child component must get data of itself, not its parents.

I use it the same way.
So you are not using SSR fetching...
Then how people actually do the SSR fetching with Next.js ?!

@linshine we have to download whatever we need at the top page level.

@lishine I'm sorry for a bit off-topic here, but in most case i don't see Router is the main issue here. Next.js router is good, declarative, convention over configuration is good. The only thing that i can't use in Next.js is the data fetching methods like getInitialProps,...
In my apps, each component will need to declare its own data right in the same place, in the same file, whatever it's graphql or rest.
Top pages component is just for composing child components, and fetching data is not its job. Child component must get data of itself, not its parents.

Here's my sample of code that i'm using for my app for clarity:

...

As you see, you have one component with its own data. You can put it anywhere you want.

Of course, you can use Next.js pattern without any problem, but in my case, i prefer isolation for data and component as much as possible for easier maintainance and refactoring later.

@revskill10 Why can't you have the child declare it's data fragment and then have the parent include that fragment in the top-level query? Especially as you create more child-associated fragments, you have perfect data isolation. Having a parent query with a child fragment is no different than having that child declared in JSX, so you have the same level of coupling but avoid request waterfalls (much harder in REST, sadly).

We have a Relay-Next app and this pattern works perfectly, with data-encapsulation and reusable composition, and we leverage getInitialProps with ease.

@merrywhether Not to mention about the much harder in REST, your approach has a problem that, you can't decide which fragments will be SSG/SSR or will be CSR.
In my approach, it's as easy just as importing that component with { noSSR: true/false} .

I find the lock-in to a vendor specific routing library that does not share an underlying implementation with any major routing library to be extremely concerning.

I recently did a review of Next.js to evaluate whether it should be used as the base for the common core shared between a number of frontend applications being built for our current client. While Next.js has potential; this router is one of the major reasons I ended up rejecting Next.js and instead keeping CRA as the base for these applications.

I do understand the difficulty of using the component based top-level API of react-router/@reach/router as the base for SSR. But that isn't a good reason for the underlying implementation being entirely custom. Gatsby's SSG has the same concerns as Next.js and a semi-similar file based routing structure; but to my understanding Gatsby uses @reach/router under the hood to power its routing implementation instead of reinventing the wheel or exposing a Link API that is incongruous with the Link API used by other libraries.

@dantman may i ask what did you choose for Next.js alternative. Assuming you needed server side rendering.... I have been trying out After.js maybe it can provide some inspiration/ideas how to implement in Next.js if not being supported by zeit.

@dantman may i ask what did you choose for Next.js alternative. Assuming you needed server side rendering.... I have been trying out After.js maybe it can provide some inspiration/ideas how to implement in Next.js if not being supported by zeit.

Sorry, I don't have a helpful answer for you. SSR wasn't a hard requirement so we just kept using CRA, which the prototype was built with.

I thought Next.js had promise as a universal framework since it recently gained the ability to have a mix of SSR/SSG/client-only pages and could run as an isomorphic app or as a static/PWA app. The WebPack customization was tempting because CRA has been making using globalize-compiler hard. The Next.js server was a neutral/positive because we needed an API server anyways for a GraphQL/REST bridge. And the option of SSR/SSG was a positive since I'm building the core a half dozen applications will be based on and it's not impossible it could end up useful in the future. However I also had some issues with the way Next.js' SSR works and these positives were not worth the trouble caused by the router.

@dantman

I find the lock-in to a vendor specific routing library that does not share an underlying implementation with any major routing library to be extremely concerning.

It’s quite strange to qualify an open source component with an API that hasn’t changed in 3 years due to its great stability and “product/market fit” as “lock-in”

Next.js has succeeded and continues to show the growth that it does because of its router and not in spite of it.

As many have seen me comment on Twitter, once upon a time we seriously entertained merging in some router (although I’m confused as to which one is the standard in your mind, Reach or React Router, and at what major version). But the world pulled us in other interesting directions. In reality, we didn’t even know what the point was of adding it, because everyone kept succeeding with Next.js and building wonderful products.

When I indeed would inquire to people why they wanted a different router API, the reason that most frequently would come up is because people were stuck and frustrated with home grown framework solutions built on a router, and they couldn’t wait to migrate to Next. It wasn’t a reason rooted in product design.

When I say that Next succeeded because of it router, it’s because it eliminated two problems:
1️⃣ The idea of having to choose a router. Us removing this is in retrospect an excellent decision. In all the time Next.js with its stable router has existed, the router world has split up and launched all kinds of API changes

2️⃣ The learning curve of a router. Many workshops and tutorials have been given about routing, but the Next.js filesystem-first routing takes 2 seconds of explain and gives you the platform to build incredible things, and you move right into product development

I want to stress this last point. Consider one of the newest and fastest growing websites in the world, TikTok.com, built on Next.js. The entire routing topology of that website can be explained with that two second learning curve. https://www.tiktok.com/@sheezus.christ/video/6824007862197439750 is pages/[user]/video/[id].js and https://www.tiktok.com/trending is pages/trending.js

Many of the recent Next.js innovations you mention you like, like hybrid static/SSG/SSR, are also enabled by our router design. In fact, the router will also enable many other similar optimizations that are coming in the future to deliver less JS to clients.

However I also had some issues with the way Next.js' SSR works and these positives were not worth the trouble caused by the router.

Would love to hear about these. The example above is powered by Next.js hybrid static/SSR and we see lots of success with it across the board!

This is such a funny thread. Next has concrete reasons for avoiding waterfall routing (aka react-router and friends) as getInitialProps enables a lot of performance optimizations, and Next's approach is turning out to be quite popular, especially as some people specifically want those optimizations. Performance comes with design tradeoffs, and sometimes you may prefer to choose design over performance, but that doesn't make the tool wrong, just wrong for you for a specific project.

Ultimately, react-router isn't the be-all-end-all of routing solutions. It has its pros and cons, as does Next. FWIW, Facebook doesn't use react-router, and they probably know a thing or two about using React. So it's fine to have alternatives, and actually one of the great things about the JS ecosystem: let different things compete in the arena of ideas and ultimately we all move forward.

Since I’m closing the issue, I want to make it clear that we are always open to comments, feature requests and bug reports on the routing capabilities.

Ideally, those would be product driven (“I need to do X but it’s not possible” or “Y is possible but not ergonomic”). We are always on the lookout for improvements that help you make lean websites and applications with great user experiences 🤗

@rauchg Can you explain the reason behind having two props, href and as to a link? Why can't it infer the intended page based on the value of the as prop?

For example in express if I have a route as /blog/:slug, i can just send a http request to /blog/hello-world and expect the router to route to it. I don't have to send both /blog/:slug and blog/hello-world to the server.

@avin-kavish that’s a great question. There’s an important distinction to be made between what the URL displays and what page is to be loaded. As a matter of fact TikTok uses that to render certain things in modals, that when you refresh the page become other pages. However, one big area of improvement here is that we should perhaps statically enforce that you’re referencing a valid page that exists in the file-system. We will follow up by creating a Discussion on this and tag you!

I think an issue already exists for that https://github.com/zeit/next.js/issues/8207

In case someone watched this issue for a react-router like "nested routes" feature which allows navigating to new pages without re-rendering everything like I was, there is actually a dedicated issue you can watch and vote for. I just found out about that one: https://github.com/zeit/next.js/issues/8193

@rauchg

To be clear in this my primary issue is not the lack of a RR/reach style component API, I am fine with a SSR capable file/config based API. Although I am a bit optimistic that in the future Suspense could make alternate SSR/routing APIs viable. My primary issue is the router being completely custom with any common concerns in the implementation being re-implemented instead of shared with any part of the wider React community.

I find Gatsby's approach to be acceptable. They have a SSG capable file+config based routing API and export their own enhanced Link component; but they use @reach/router to power the underlying implementation.

I find the lock-in to a vendor specific routing library that does not share an underlying implementation with any major routing library to be extremely concerning.

It’s quite strange to qualify an open source component with an API that hasn’t changed in 3 years due to its great stability and “product/market fit” as “lock-in”

The router is intrinsically tied to Next.js. Adopting Next.js for one reason means being tied to the router. If we adopt Next.js and later discover that next/router has a limitation that turns out to be crippling for something we're trying to do there is absolutely no reasonable escape hatch. "Lock-in" is a perfectly fine descriptor for that.

Lock-in alone wouldn't be a major issue. Gatsby's use of @reach/router would also be lock-in. But @reach/router is used outside of just Gatsby. I don't have to trust the Gatsby community alone to maintain the entire router stack; I can trust that a larger community relies on it and there are more stakeholders involved (specific to the routing stack) to ensure it's maintained, keeps up with difficult routing issues (e.g. accessibility), and is depended on by a wider more varied community that will likely share any potentially crippling issues we could encounter in the future.

although I’m confused as to which one is the standard in your mind, Reach or React Router, and at what major version

In terms of the de-facto standard of what <Link> should look like. Both Reach and React Router (RR) share very similar APIs. e.g. <Link to='/about'>About</Link> is valid in both RR and Reach (and of course by extension Gatsby). Which makes Next.js' idiosyncratic <Link href='/about'><a>About</a></Link> so much more jarring.

In terms of what I think Next.js should use. I'm not tied to a specific library, if Next.js were already using one I wouldn't suggest switching to another. My major concern is that the routing implementation be shared with a library with a wider community outside of Next.js.

In practice though that's relatively moot. As so far I haven't seen any React router besides RR and Reach with a large userbase. And RR and Reach are going to become one library, so whichever you start with the end result will be the same.

I tried Next a while back but lack of flexibility on the router led me to discover a Razzle implementation called After.js https://github.com/jaredpalmer/after.js?utm_source=hashnode.com.

As React Router is just a package can we not import it and limit rendering to client side only so it works like an SPA where its needed and give us nested component routes? Isnt React router just a set of components to be (potentially) embedded in pages and loaded with the Next.js page router like any other components?

I read in earlier threads that zeit plans to integrate RR is that still true today?

Why don't we allow nested routes in next.js router as a last resort and make it clear that these areas will not be pre-rendered. At the very least it will save us the effort of having to avoid writing the if conditions that we have to inevitably write when we want a sub-resource in the page to change based on the route.

I'm adding my vote on this issue.

Another pro, not mentioned, is that RR its more testable, (AFAIK there is no official nextjs API for router testing), it has MemoryRouter for wrapping tests and stories.

Next.js has a lot of good features (automatic WebPack, static files, and TypeScript like CRA but for more than just PWAs; API routes; serverless support, Fast Refresh, and even experimental Expo support for web+native apps) and a core for SSR and SSG even if the API for it isn't great. But while the built-in routing system and SSR/SSG works for some; for others they hobble development because the limits of both APIs offer the wrong trade-offs for said project.

How about a compromise. Next.js already has plugins. Instead of replacing the router internally what if we separated the router and SSR API (i.e. the getStaticProps/getServerSideProps in route files) from the core of Next.js. e.g. We could put the very fundamental core parts in @next/core and move the current opinionated router and get*Props APIs to @next/router. For simplicity and backwards compatibility next could be a framework that re-exports @next/core and comes pre-configured with Vercel's preferred router. But then it would be possible for the community develop routers and SSR/SSG APIs with different trade-offs that are better suited to projects that would otherwise be stuck throwing out the good parts of Next.js with the bathwater.

Some thoughts on what the Next.js core would require the router plugin to provide:

  • Given a request { url, body, etc } the core would expect the router plugin to render this request to a document (string or streaming) or throw a response (i.e. 404 or redirect).
  • On export the core would expect the router plugin to provide a list of pages that need to be rendered.

@next/router would probably implement the same patterns via the api by doing things like:

  • Given a request, identifying the route file responsible and rendering as normal
  • On the client doing something similar to whatever it currently does to know when to call the SSR API and render the route it needs (possibly moving the API based SSR API to a normal looking API route)
  • On export using the pages file tree and getStaticPaths to provide the list of static pages

I could probably see myself experimenting with a router plugin using React Router v6 with @apollo/react-ssr and Suspense with react-ssr-prepass or [email protected]. Which forgoes SSR-only routes for isomorphic SSR routes and implements SSR/SSG without a restricting get*Props style API.

What I realised is, nested routing + SSG is achievable without breaking the current API. So we have getStaticPaths at the moment, we can use that to hint at nested routes for pre-rendering. For example,

Given a route /foo/[...slug],

function FooPage() {

  return (
      <Switch>
          <Route path="/foo/bar">
              <SomeResource />
              <Route path={`${parenthPath}/baz`} component={SomeSubResource} />
          </Route>
          .... more routes
      </Switch>
  )
}

can be pre-rendered with,

export async function getStaticPaths() {

  return {
    paths: [
      { slug: [ 'bar' ] },
      { slug: [ 'bar', 'baz' ] },
    ],
  }
}

With the way it is at the moment next.js is like a server side framework with the convenience of creating pages in react. It doesn't feel as powerful as react-router. Directory based routing may have it's place in building consumer facing sites like tiktok as mentioned before, but for complex data driven application portals, nested routing is still king. It is why single page applications were created in the first place, it allows for changing bits of the UI without having to replace the entire page. This can be leveraged to model resource-subresource relationships quite conveniently. As it stands, I may use next.js if I were to build the public pages of a consumer site like an e-commerce site but when I need to build the private areas such as admin, buyer & seller portals I would switch to CRA.

@avin-kavish the main issue is not to make it work, but to make it optimized: each page on Next.js default have their own bundle and are optimized for speed.

If you start adding a lot of content/sub-content in a single page like you did, you could end up with a quite big bundle in the end (which is not "terrible" per se, but you should just be aware of the trade-offs). You might be able to do some manual optimization with next/dynamic thought :)

@rauchg the only dimension isn't whether next router is good or bad. Another very important thing is migration to and from next.js and community support, and https://github.com/vercel/next.js/issues/1632#issuecomment-633310614 put it well. Next.js is such a good solution for abstracting away a lot of the boilerplate a high-quality SSR app needs, and as such it's a very inviting migration target for many web apps. The problem right now is that it would need a complete routing rewrite both for migrating into next.js, and out of it if the need comes.

Pluggable routing suggested by @dantman earlier would solve this issue in a very elegant matter, and wouldn't require anyone to sell their principles 😉

The problem with react-router (and any nested routing solution) is that it makes static analysis much harder because the relevant code paths for any specific URL are not available without running (or simulating) the code itself. Next is more than just a "put UI on a webpage" framework, which is why for instance they worked with the Chrome team on creating more highly optimized bundling strategies.

react-router users are used to using react-loadable directly since it rr delegates that responsibility entirely to end-users, but Next tries to abstract and automate this which isn't easy. The proposed pluggable router approach would probably have to involve router plugins providing extensive build-time information to the framework in order to achieve the same type of output, since every router would have to know how to generate such information based on its own patterns.

Purely speculation, but I imagine a lot of things are in limbo while React finishes up Suspense, since making that a first class pattern in the library will greatly affect all of the router libraries and also give a concrete foundation upon which to build async/loadable bundle patterns.

Long story short / a good summary of below: There is no such thing as a "one-size fits all solution". Everything has trade-offs. Every "advantage" of the way Next.js currently does things comes with a disadvantage. What advantages/disadvantages are are most important is something that is different for each project. Hence, the recommendation for a pluggable router/ssg/ssr architecture. Different projects need different things and right now Next.js only works for the projects whose priority on trade-offs aligns with the way things are hardcoded in Next.js.

The problem with react-router (and any nested routing solution) is that it makes static analysis much harder because the relevant code paths for any specific URL are not available without running (or simulating) the code itself.

Honestly that only matters if you are using SSG and have a bunch of non-dynamic routes. If all your routes are SSG or client-only, then that's not useful. And if most of your routes are dynamic then you have to explicitly declare them using getStaticPaths anyways. Which would be the same amount of work as explicitly defining the routes in a hypothetical Next.js plugin that just uses raw react-router without modification and asks you to explicitly define static routes.

It is an advantage sure, and some teams will want that. However that is only one sub-group of potential Next.js users. There are other groups who may want some of the advantages that RR or another routing library provides and the need to explicitly declare static routes is an acceptable tradeoff or a non-issue. For example, my last few projects have been the kind of B2B/B2C apps where 100% of things are behind a login page and there's no point statically rendering any of it. Next.js has some advantages over CRA that would have made Next.js preferable; But things like the router were big red flags and we just kept using CRA. Those projects would have been very well suited to a Next.js with raw react-router.

This also assumes that everyone who doesn't want next/router wants to use the JSX form of react-router. That is not the only type of next/router alternative.

One other type of router would be the Gatsby.js style. Where a project still uses a filesystem based pages structure, but the internals are implemented with another routing library like react-router (Gatsby uses @reach/router internally). This kind of router plugin would give you the same static-analysis advantages. But it would also give you whatever advantages the alternate router has not related to the nested routing. e.g. Accommodating potential preferences for route API, better handling of accessibility, better integration into the ecosystem around that router.

And of course even within the react-router ecosystem the JSX form is not the only way to use react-router. There is also react-router-config. Which is easy to do static analysis on and also supports nested routing.

react-router users are used to using react-loadable directly since it rr delegates that responsibility entirely to end-users, but Next tries to abstract and automate this which isn't easy.

And some of us are fine with handling code-splitting ourselves. Nested routing can be more important to a project than automatic code-splitting. It's all about which trade offs are best suited to a project.

This is more of a side note, but I'm actually curious about the potential for a babel/webpack plugin that would do this automatically for routes. Which is something that would be useful outside of just the Next.js ecosystem.

Also react-loadable is an effectively defunct library (2 years since publish, not accepting bug reports). Personally I would rather manually do code splitting with @loadable/components than use something automatic built-in to Next.js based on an internal fork of react-loadable.

The proposed pluggable router approach would probably have to involve router plugins providing extensive build-time information to the framework in order to achieve the same type of output, since every router would have to know how to generate such information based on its own patterns.

Yup. That's generally how a plugin system would work. Honestly the fact that this kind of information can be provided by the plugin is an advantage, not a problem. Having this in a plugin means that should the way Next.js gathers this information not be suitable for some types of projects' needs, it can be replaced with one that does fit the needs of those projects. But without needing to fork and rewrite all of Next.js to do so.

Purely speculation, but I imagine a lot of things are in limbo while React finishes up Suspense, since making that a first class pattern in the library will greatly affect all of the router libraries and also give a concrete foundation upon which to build async/loadable bundle patterns.

This itself could actually a pretty good argument to work on a pluggable router system. Right now because all the routing and SSR stuff is hardcoded into Next.js it is not possible to easily do the experimentation into any type of future routing system within Next.js. How does Suspense affect Next.js' routing and other routing libraries? Not something you can experiment with (at least in regards to Next.js' SSR and bundling) without forking and rewriting chunks of Next.js.

Router plugins would be a great place to do this kind of experimentation. As long as the plugin API is low-level enough it would be possible to fork just the next/router plugin and try writing a [email protected] + Suspense based version of that router. And because this is a plugin (not a fork of all of Next.js), it would be easy to opt-in to the experiment and test out the new Suspense based router. This is important now rather than later because this kind of experimentation is why [email protected] exists, to gather feedback from real projects.

@dantman I'm not disagreeing with anything you've said. It _is_ all about trade-offs. The biggest tradeoff being what the Next team spends their time on. So far, low-config high-performance SSR seems to have been their main focus. I do understand that this isn't necessarily relevant for all users, but it is the angle Next initially used to stand out (which is why we choose them at work). They've recently dug more into SSG, seemingly due to the popularity of Gatsby and Jamstack, but they're still best for SSR imo.

Honestly that only matters if you are using SSG and have a bunch of non-dynamic routes

I'm not sure what you mean by this, as SSG vs SSR doesn't really matter for trying to deliver the smallest possible JS payload for the first page ("critical path" JS), nor do dynamic routes. Minimizing critical path assets _is_ generally pretty important for SSR apps (thus all the effort) so this is appreciated. And honestly, if all you're making are login-walled CSR-only apps, then Next _does_ have a lot of downsides compared to CRA (SSR will never be as convenient as CSR). It sounds like you're discounting those apps that are actually doing runtime SSR (with server-side handling of login/personalization) specifically for perf wins. Not everything fits into the SSG vs CSR dichotomy.

some of us are fine with handling code-splitting ourselves

Some of us are are quite capable handling webpack, react-dom/server, etc ourselves too. Next's goal so far has seemed to be to make such ejection rarer and rarer just like CRA. And you're right, I should have said react-loadable-alike, because there are lots of solutions in that space, and they are only getting more exotic with the emerging data-plus-code patterns from libraries like Relay.

Ultimately, I don't disagree that a pluggable router system might be nice. I was just pointing out that it would be a lot of work for the Next team to remove things that are central tenets of the framework (like bundle-splitting logic) and extracting them into a pluggable architecture. And my speculation was highlighting the fact that I wouldn't want to start designing a foundational change to my library that could easily be upended by upcoming changes to my core dependency. I certainly agree that some aspects of Next's design _are_ limiting, but for the most part those limits make sense given their design constraints thus far.

Honestly that only matters if you are using SSG and have a bunch of non-dynamic routes

I'm not sure what you mean by this, as SSG vs SSR doesn't really matter for trying to deliver the smallest possible JS payload for the first page ("critical path" JS), nor do dynamic routes.

We're probably thinking of different reasons why the ability to statically analyze what routes exist is necessary. Assuming we're both talking about "static analysis" as "the ability to identify the list of routes (e.g. ['/about', '/', '/profile']) at build time simply by reading the code".

It sounds like you're talking about some type of JS bundle optimization? Which I haven't found any information on in the documentation, so I'm not aware of exactly what type of optimization based on static route analysis you're thinking of.

My thought was that this static analysis of routes was primarily useful for SSG. i.e. Because the pages/about.js file exists when you build your site Next.js knows that an /about route exists and it needs to pre-render the html for this route, even though you never explicitly told it there's an /about route to pre-render.

SSR doesn't need pre-built html since it only does that when a request comes in (at which point it does run the code and has one path to render). Client-rendered pages don't have pre-rendered html at all. And if your SSG page is dynamic then you need to declare all the paths anyways. Hence my thoughts.

And honestly, if all you're making are login-walled CSR-only apps, then Next _does_ have a lot of downsides compared to CRA (SSR will never be as convenient as CSR).

What downsides are you thinking of in Next.js in regards to CSR apps? Aside from the aforementioned router issues.

To my understanding Next.js supports the full gamut of SSR/SSG/CSR routes. So it is supposedly still suitable for writing login-walled CSR-only apps.

Personally my perspective is definitely from someone writing a lot of largely CSR apps, with occasional SSR and SSG needs, wanting to have a single robust toolkit for all my projects, no mater what mix of SSR/SSG/CSR they need.

From my experience CRA has a fair number of disadvantages even within CSR-only apps that could make Next.js' CSR-pages advantageous. WebPack config customization without ejecting is a big one. This caused me a lot of pain when I couldn't simply use the globalize-compiler WebPack plugin when I was adding i18n to an app. The ability to opt-in to SSR/SSG for specific pages even if most of the pages are CSR is also an advantage (e.g. 99.9% of your pages are CSR and behind a login page; but you have landing page and maybe terms/contact pages you want SSG or SSR on). Can't do any of those things reasonably with stuff like CRA.

some of us are fine with handling code-splitting ourselves

Some of us are are quite capable handling webpack, react-dom/server, etc ourselves too. Next's goal so far has seemed to be to make such ejection rarer and rarer just like CRA

Honestly, manually doing route based code-splitting (making sure you modify one to use your route components via React.lazy or an alternative library instead of a direct import) is a far far far ways away from manually managing a custom WebPack config or writing your own SSR handlers with react-dom/server.

It's entirely reasonable to not want to manually write a whole WebPack config or a custom SSR server (i.e. want to use a widely used framework like Next.js), but still be ok with using react-router and manually doing the route based code-splitting. Especially if opting in to automatic route base code-splitting means loosing the widely used router library you're using and using a router missing a number of features you may need with an API very different than any of the routers in wider usage.

I always land in this issue when searching for a way to integrate react-router with NextJS that doesn't require to create a custom server, so I decided to give it a try myself.

With react-router v6 (beta), create a custom _app:

// _app.js || _app.tsx
import * as React from 'react'
import App from 'next/app'
import NextRouter from 'next/router'

export default class CustomApp extends App {
    render() {
        const { Component, pageProps } = this.props

        if (process.browser) {
            const { Router } = require('react-router-dom')
            const { createMemoryHistory } = require('history')
            const history = createMemoryHistory({
                initialEntries: [this.props.router.asPath],
            })

            history.listen(function ({ action, location }) {
                const url = {
                    hash: location.hash,
                    pathname: location.pathname,
                    search: location.search,
                }
                switch (action) {
                    case 'PUSH':
                        return NextRouter.push(url)
                    case 'REPLACE':
                        return NextRouter.replace(url)
                    default:
                        return void 0
                }
            })

            return (
                <Router location={history.location} navigator={history} action={history.action}>
                    <Component {...pageProps} />
                </Router>
            )
        } else {
            const { StaticRouter } = require('react-router-dom/server')
            return (
                <StaticRouter location={this.props.router.asPath}>
                    <Component {...pageProps} />
                </StaticRouter>
            )
        }
    }
}

Why

It isn't easy to manage _optional catch all routes_ in NextJS (e.g: /foo/[[...bar]].js), so I'm exploring a way to be able to use react-router for this kind of pages. Maybe others have different reasons but that's my main concern and react-router provides a nice API, specially in v6 which is currently in beta.

How it works

It just creates a custom MemoryRouter instead of a BrowserRouter so we don't mess up browser history by having NextJS router & NextJS router. It listens to the memory history changes for PUSH and REPLACE so you can use react-router hooks or Link to navigate but under the hood, it'd be calling NextJS router methods .push and .replace.

Calling NextJS router methods is needed, otherwise route changes won't actually trigger NextJS get*Props methods. In other words, it'd work similarly as shallow option using NextJS Link. The downside of using react-router's Link is that there is no prefetch. However, you can still use NextJS Link instead and react-router can still react to route changes.

The cool thing about it is that you can now leverage NextJS dynamic and react-router routes and do things such as:

// /foo/[[...bar]].js
import * as React from 'react'
import { Route, Routes } from 'react-router-dom'
import dynamic from 'next/dynamic'

const Home = dynamic(() => import('src/views/Home'))
const About = dynamic(() => import('src/views/About'))
const Navigation = dynamic(() => import('src/views/Navigation'))

export default function Root() {
    return (
        <>
            <Navigation />
            <Routes>
                <Route path="/foo/" element={<Home />} />
                <Route path="/foo/about" element={<About />} />
            </Routes>
        </>
    )
}

Anyways, I hope this helps someone. I haven't used this in production and this code is from a local playground I have, so probably there are things that could be improved but it's a start.

Using React Router with Next.js 9.5+

If you're using Next.js 9.5 or later the correct way to do this is with Rewrites. _Do not use a custom server_! There is a detailed tutorial on how to do this here: https://colinhacks.com/essays/building-a-spa-with-nextjs

The basic idea:

  1. Create a custom App (/pages/_app.tsx)

  2. Return null if typeof window === "undefined". This is required to prevent react-router from throwing errors during the SSR step!

// pages/_app.tsx

import { AppProps } from 'next/app';

function App({ Component, pageProps }: AppProps) {
  return (
    <div suppressHydrationWarning>
      {typeof window === 'undefined' ? null : <Component {...pageProps} />}
    </div>
  );
}

export default App;

The suppressHydrationWarning attribute is to prevent warnings that React throws when the server-rendered content disagrees with the client-rendered content.

  1. Rewrite all routes to the homepage
// next.config.js

module.exports = {
  async rewrites() {
    return [
      // Rewrite everything else to use `pages/index`
      {
        source: '/:path*',
        destination: '/',
      },
    ];
  },
};

Then you can use React Router like normal! There is a lot more context/explanation in the linked tutorial but this will get you started. https://vriad.com/essays/building-a-spa-with-nextjs

@colinhacks Nice solution can confirm it works. Something to think about maybe is moving the app to its own page like app.js or routes.js or something. Then having the rewrites to

// next.config.js

module.exports = {
  async rewrites() {
    return [
      {
        source: '/app/:path*',
        destination: '/app',
      },
    ];
  },
};

Just something to think about, your solution is the best I found.

Was this page helpful?
0 / 5 - 0 ratings