question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

/basePath redirects to root in NextJS 13 (appDir)

See original GitHub issue

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Version 21.6.0: Mon Aug 22 20:19:52 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T6000 Binaries: Node: 16.14.0 npm: 8.3.1 Yarn: 1.22.18 pnpm: N/A Relevant packages: next: 13.0.0 eslint-config-next: 13.0.0 react: 18.2.0 react-dom: 18.2.0

What browser are you using? (if relevant)

Firefox 106.0.1

How are you deploying your application? (if relevant)

No response

Describe the Bug

In NextJS 13, the document at /myapp instantly redirects to the root path /.

const nextConfig = {
  basePath: '/myapp',
  experimental: { appDir: true },
  reactStrictMode: true,
  swcMinify: true,
}

During this redirect, or replaceState, the /myapp entry is not registered in history.

While the root app/layout.tsx and app/page.tsx is now rendered on screen, the website becomes a 404 if we reload the location / without the /myapp segment.

It would appear that basePath works differently or not at all in version 13 👀

Expected Behavior

The /{basePath} should stick around in the location so that we can reload forever.

Link to reproduction

https://github.com/wiredearp/basepath-redirect

To Reproduce

Create a website with create-next-app, set basePath and enable appDir. Then run dev and visit the /{basePath} to witness the redirect. This setup can be cloned from the reproduction repo. Thanks for digging in!

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:23
  • Comments:5

github_iconTop GitHub Comments

1reaction
alexdgourlaycommented, Dec 6, 2022

Can confirm also.

The workaround we’ve come up with makes use of the redirects functionality in the config.

module.exports = {
  basePath: '/myapp',
  async redirects() {
    return ([
      {
        source: '/',
        destination: '/myapp',
        permanent: true,
        basePath: false,
      },
    ]);
  }
};

Of course this is increases loading time with the added redirect.

0reactions
cachhocommented, Dec 27, 2022

I deployed my project to production with this issue, here’s what I’ve learned. It covers a case where you have another page at root, and how to deal with it in nginx.

Since I have multiple subpages, including dynamic routes directly under root I had to add a whole set of rules following @alexdgourlay’s instructions. Keep in mind that you can use regex, in my case this was required to separate the dynamic routes. This worked in dev, however in prod I had to give up on this idea and instead created a new subfolder above the dynamic route, so it doesn’t site directly under root.

/classic
    /[agent]
/new
    /[country]
        /[agent]
            /[line]

Here’s what it looks like in my example, my basepath would be /my-basepath:

async redirects() {
    return [
      {
        source: '/new/:country([A-Z][a-z.%20{%20&}]+)',
        destination: '/my-basepath/new/:country',
        permanent: true,
        basePath: false,
      },
      {
        source: '/new/:country([A-Z][a-z.%20{%20&}]+)/:agent/',
        destination: '/my-basepath/new/:country/:agent',
        permanent: true,
        basePath: false,
      },
      {
        source: '/new/:country([A-Z][a-z.%20{%20&}]+)/:agent/:line',
        destination: '/my-basepath/new/:country/:agent/:line',
        permanent: true,
        basePath: false,
      },
      {
        source: '/',
        destination: '/my-basepath',
        permanent: true,
        basePath: false,
      },
      {
        source: '/classic',
        destination: '/my-basepath/classic',
        permanent: true,
        basePath: false,
      },
      {
        source: '/classic/:agent',
        destination: '/my-basepath/classic/:agent',
        permanent: true,
        basePath: false,
      },
    ];
  },

However, in production I have another site at root (the reason I’m using a base path), and unlike dev, (this is my understanding), because the browser goes to root for a split second before the redirect can kick in, my nginx for the site at root is in control and the redirect can’t resolve.

The solution for this was to add more rules for nginx. These need to be uniquely identifiable, so that nginx knows they came from the nextjs app and can send you back there.

location /my-route/ {  
        return 301 $scheme://my-site.com/my-basepath/$request_uri;
    }

At this point I decided to give up on /basepath/[country], because I would have to figure out how to rewrite root/[country] in nginx, without redirect any of my main site at root’s subpages. So I moved [country] into /new, in my example I just have to redirect /new and /classic in nginx. One of the problems caused by this is that my site at root can’t have /my-route, because that would be redirected to your nextjs-app.

The next problem is that you can’t link back to / in your nextjs-app. This will direct you to the root of your page at route, and I can’t map a redirect for that. My solution was to add these two redirects:

      {
        source: '/my-basepath/home',
        destination: '/my-basepath',
        permanent: true,
        basePath: false,
      },
      {
        source: '/my-basepath/my-basepath/home',
        destination: '/my-basepath',
        permanent: true,
        basePath: false,
      },

everywhere I have a link to / in my next-app, I replaced it with /my-basepath/home. So yes, this goes on top of the basepath, so the link on the web looks like this /my-basepath/my-basepath/home:

<Link href="/my-basepath/home">
    <Image src={Logo} alt="website logo"></Image>
</Link>

If use the broken redirect from within the app, the base path is swallowed as we know, and it goes to /my-basepath/home (in my case /my-basepath/home), which is where the first of the two added redirects kicks in. If someone opens in a new tab, the second rule kicks in. Reminder, I’m doing this because /basepath redirects to root, and I can’t redirect the root of my domain. This leaves me with an ugly home link.

Because I handle it through nginx now, all of the nextjs/next.config.js redirects except those for home could be removed. However, this won’t work in dev, so I’ll personally be keeping them.

Bottom line, things get worse in production when you actually have something at root. You need lots of redirects which makes links ugly and the performance slow. And if you change something you have to look in lots of places. I’m sure there are better ways to do this, and that nginx has advanced functions to deal with this.

I know it’s Christmas and everyone deserves their time off. Images with basepath were fixed, and I hope routes/links are next. Thanks devs!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Base Path - next.config.js
To deploy a Next.js application under a sub-path of a domain you can use the basePath config option. basePath allows you to set...
Read more >
Advanced Features: `src` Directory - Next.js
Save pages under the `src` directory as an alternative to the root `pages` directory.
Read more >
Advanced Features: Output File Tracing - Next.js
Next.js automatically traces which files are needed by each page to allow for easy deployment of your application. Learn how it works here....
Read more >
Next.js 13 Upgrade Guide
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { appDir: true, }, }; module.exports = nextConfig;. Then, create a new app directory ......
Read more >
next.config.js: Introduction
js module, not a JSON file. It gets used by the Next.js server and build phases, and it's not included in the browser...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found