Next.js Discord

Discord Forum

`Router.push` with `basePath` Results in `basePath` being Repeated Twice

Unanswered
Dan6erbond posted this in #help-forum
Open in Discord
I'm deploying a Next.js app using a mix of the App and Pages Router to Coolify. I'm trying to use basePath which has worked fine in the past but all of a sudden seems to have broke, and now whenever I call router.push() it will redirect to /basePath/basePath. I made sure to disable Strip Prefixes in Coolify so Next.js always sees the full path, does anyone know what might be causing this?

18 Replies

Brown bear
This usually happens if you’re passing the basePath manually into router.push. When using basePath, you should only push relative paths like router.push('/page'), not router.push('/basePath/page') or it’ll double it.

Also double check next.config.js to make sure basePath is still correct and matches what you’re using.

Since you’ve already disabled Strip Prefixes in Coolify, it’s likely just the push path causing this.
@Brown bear This usually happens if you’re passing the basePath manually into router.push. When using basePath, you should only push relative paths like router.push('/page'), not router.push('/basePath/page') or it’ll double it. Also double check next.config.js to make sure basePath is still correct and matches what you’re using. Since you’ve already disabled Strip Prefixes in Coolify, it’s likely just the push path causing this.
Thanks! My router.push is super simple and doesn't include the basePath:
      router.push(
        `/cars/${router.query.id}/performance/drag-sessions/${data.createDragSession.id}`, undefined, {}
      );


My next.config.ts uses process.env.BASE_PATH which is set at build time using Docker build args in Coolify:
const nextConfig: NextConfig = {
  reactStrictMode: true,
  output: "standalone",
  basePath: process.env.BASE_PATH,
  env: {
    BASE_PATH: process.env.BASE_PATH,
  },
  images: {
    remotePatterns,
  },
  transpilePackages: ["next-auth"],
};
@American Sable hope this answers your question too.

The value is /app but when calling router.push I get /app/app.

For additional reference, my middleware does use the basePath for Auth.js redirects but I don't think that's relevant:
import { NextResponse } from "next/server";
import { auth } from "@/auth";

const basePath = process.env.BASE_PATH ?? "";

export default auth((req) => {
  if (!req.auth && !req.nextUrl.pathname.startsWith("/auth")) {
    if (req.nextUrl.pathname.startsWith("/auth")) return;
    if (req.nextUrl.pathname.startsWith("/share")) return;
    if (/^\/cars\/[0-9a-zA-Z\-]+$/.test(req.nextUrl.pathname)) return;
    if (/^\/cars\/[0-9a-zA-Z\-]+\/mods$/.test(req.nextUrl.pathname)) return;
    if (/^\/cars\/[0-9a-zA-Z\-]+\/build\-log$/.test(req.nextUrl.pathname))
      return;
    if (/^\/cars\/[0-9a-zA-Z\-]+\/gallery$/.test(req.nextUrl.pathname)) return;
    if (/^\/cars\/[0-9a-zA-Z\-]+\/opengraph\-image$/.test(req.nextUrl.pathname))
      return;

    const newUrl = new URL(basePath + "/auth/signin", req.nextUrl.origin);

    let pathname = req.nextUrl.pathname;
    if (!pathname.startsWith(basePath)) {
      pathname = basePath + pathname;
    }

    newUrl.searchParams.set("callbackUrl", pathname);
    return NextResponse.redirect(newUrl);
  }
});

export const config = {
  matcher: [
    "/((?!api|_next/static|_next/image|favicon.ico|favicon.png|favicon-96x96.png|web-app-manifest-192x192.png|web-app-manifest-512x512.png|manifest.json|apple-touch-icon.png|icon0.svg|apple-icon.png|icon1.png).*)?",
  ],
  unstable_allowDynamic: ["**/node_modules/lodash/*.js"],
};


The full codebase is [here](https://github.com/dan6erbond/revline).
@Asian black bear Please don’t use LLM-generated responses.
Brown bear
I'm not good at explaining things good, atleast with my english fluency, that's why it might look like AI generated to you. [It's enhanced].

Anyways, if that's not allowed. It's okay! Sorry.
@Dan6erbond Thanks! My `router.push` is super simple and doesn't include the `basePath`: ts router.push( `/cars/${router.query.id}/performance/drag-sessions/${data.createDragSession.id}`, undefined, {} ); My `next.config.ts` uses `process.env.BASE_PATH` which is set at build time using Docker build args in Coolify:ts const nextConfig: NextConfig = { reactStrictMode: true, output: "standalone", basePath: process.env.BASE_PATH, env: { BASE_PATH: process.env.BASE_PATH, }, images: { remotePatterns, }, transpilePackages: ["next-auth"], }; <@173557815326015488> hope this answers your question too. The value is `/app` but when calling `router.push` I get `/app/app`. For additional reference, my middleware does use the basePath for Auth.js redirects but I don't think that's relevant:ts import { NextResponse } from "next/server"; import { auth } from "@/auth"; const basePath = process.env.BASE_PATH ?? ""; export default auth((req) => { if (!req.auth && !req.nextUrl.pathname.startsWith("/auth")) { if (req.nextUrl.pathname.startsWith("/auth")) return; if (req.nextUrl.pathname.startsWith("/share")) return; if (/^\/cars\/[0-9a-zA-Z\-]+$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/mods$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/build\-log$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/gallery$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/opengraph\-image$/.test(req.nextUrl.pathname)) return; const newUrl = new URL(basePath + "/auth/signin", req.nextUrl.origin); let pathname = req.nextUrl.pathname; if (!pathname.startsWith(basePath)) { pathname = basePath + pathname; } newUrl.searchParams.set("callbackUrl", pathname); return NextResponse.redirect(newUrl); } }); export const config = { matcher: [ "/((?!api|_next/static|_next/image|favicon.ico|favicon.png|favicon-96x96.png|web-app-manifest-192x192.png|web-app-manifest-512x512.png|manifest.json|apple-touch-icon.png|icon0.svg|apple-icon.png|icon1.png).*)?", ], unstable_allowDynamic: ["**/node_modules/lodash/*.js"], }; The full codebase is [here](https://github.com/dan6erbond/revline).
Brown bear
Then, the double /app/app issue is likely coming from process.env.BASE_PATH, make sure it's set.

and when you set base path in next config, Next.js automatically prepends it to all routes, including router.push. you actually don’t need to handle it yourself anywhere else.

after this, try removing the part where you manually add the basePath in the middleware, it should work.
<Link> also works so the issue is alone with router.push.
And like I said, my router.push call doesn't include the basePath:
router.push(`/cars/${router.query.id}/performance/drag-sessions/${data.createDragSession.id}`)
after this, try removing the part where you manually add the basePath in the middleware, it should work.
I only do that in the callback URL which is used by Auth.js in a server-side redirect, again, doubt that should have any effects.
@Dan6erbond Thanks! My `router.push` is super simple and doesn't include the `basePath`: ts router.push( `/cars/${router.query.id}/performance/drag-sessions/${data.createDragSession.id}`, undefined, {} ); My `next.config.ts` uses `process.env.BASE_PATH` which is set at build time using Docker build args in Coolify:ts const nextConfig: NextConfig = { reactStrictMode: true, output: "standalone", basePath: process.env.BASE_PATH, env: { BASE_PATH: process.env.BASE_PATH, }, images: { remotePatterns, }, transpilePackages: ["next-auth"], }; <@173557815326015488> hope this answers your question too. The value is `/app` but when calling `router.push` I get `/app/app`. For additional reference, my middleware does use the basePath for Auth.js redirects but I don't think that's relevant:ts import { NextResponse } from "next/server"; import { auth } from "@/auth"; const basePath = process.env.BASE_PATH ?? ""; export default auth((req) => { if (!req.auth && !req.nextUrl.pathname.startsWith("/auth")) { if (req.nextUrl.pathname.startsWith("/auth")) return; if (req.nextUrl.pathname.startsWith("/share")) return; if (/^\/cars\/[0-9a-zA-Z\-]+$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/mods$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/build\-log$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/gallery$/.test(req.nextUrl.pathname)) return; if (/^\/cars\/[0-9a-zA-Z\-]+\/opengraph\-image$/.test(req.nextUrl.pathname)) return; const newUrl = new URL(basePath + "/auth/signin", req.nextUrl.origin); let pathname = req.nextUrl.pathname; if (!pathname.startsWith(basePath)) { pathname = basePath + pathname; } newUrl.searchParams.set("callbackUrl", pathname); return NextResponse.redirect(newUrl); } }); export const config = { matcher: [ "/((?!api|_next/static|_next/image|favicon.ico|favicon.png|favicon-96x96.png|web-app-manifest-192x192.png|web-app-manifest-512x512.png|manifest.json|apple-touch-icon.png|icon0.svg|apple-icon.png|icon1.png).*)?", ], unstable_allowDynamic: ["**/node_modules/lodash/*.js"], }; The full codebase is [here](https://github.com/dan6erbond/revline).
Brown bear
Try removing this piece of code.
if (!pathname.startsWith(basePath)) {
  pathname = basePath + pathname;
}
That doesn't have any relevance to router.push, it's used in a server-side redirect when the user isn't logged-in.
You get sent to /auth/signin?callbackURL=myapp.com/basePath/pathname which is intentional.
Because server-side redirects require the base path, unlike router.push and <Link>.
Brown bear
I’ve looked into it as much as I can, but I don’t think I can help further on this.
wishing you the best!
Thanks!
What's weirder is I'm going through my code and I see router.push calls that work fine, it's just some that fail:
// works
router.push("/cars/create");
onClose={() => router.push(`/cars/${router.query.id}/documents`)}
const onClose = () =>
  router.push(`/cars/${router.query.id}/project`, undefined, {
    shallow: true,
  });

// doesn't work
router.push(
  `/cars/${router.query.id}/gallery/albums/${data.createAlbum.id}`
);
router.push(`/cars/${data.createCar.id}`);
router.push(`/cars/${carId}/project/mods/${data.createMod.id}`);
router.push(
  `/cars/${router.query.id}/performance/dyno-sessions/${data.createDynoSession.id}`
);