0

I have a nextjs (v13) app with basePath

  • basePath: /basePath in nextjs.config

  • NOT using a custom subdomain in production: https://DEPLOYED_URL/basePath/...

  • pages/

    • index.tsx # route: DEPLOYED_URL/basePath
      • subpath/index.tsx # route: DEPLOYED_URL/basePath/subpath

That works as expected but I want to add a new route matching a custom subdomain on Vercel WITHOUT showing the base path:

  • subdomain: https://subdomain.DEPLOYED_URL) - This is configured via a CNAME and it's valid in "vercel domains"
  • page: /new-page
  • On localhost I can easily open the page (without a subdomain) at http://localhost:3000/basePath/new-page, by prepending the base path in the url
  • When deployed, browser should display: https://subdomain.DEPLOYED_URL/new-page WITHOUT the base path

I have tried different approaches to get this to work on Vercel but neither will yield to the expected behaviour (either it's 404 on vercel or next side, or requires the base path in the url for the new page)

nextjs.config.js rewrites

rewrites() {
    return {
        beforeFiles: [
            {
                # I have also tried with a catch-all pattern: "source": "/(.*)",
                "source": '/new-page'
                has: [
                    {
                        type: 'host',
                        value: 'subdomain.DEPLOYED_URL',
                    },
                ],
                destination: '/basePath/new-page'
            },
        ]
    }
}

vercel.json rewrites

{
    "rewrites": [
      {
        "source": "/new-page",
        "has": [
          {
            "type": "host",
            "value": "subdomain.DEPLOYED_URL"
          }
        ],
        "destination": "/basePath/new-page"
      }
    ]
}

middleware rewrites

import { NextRequest, NextResponse } from "next/server"

export const getSubdomain = (host?: string | null) => {
    let subdomain: string | null = null
    if (!host && typeof window !== 'undefined') {
        host = window.location.host
    }

    if (host?.includes('.')) {
        const candidate = host.split('.')[0]
        if (candidate) subdomain = candidate
    }
    
    return subdomain
}

export async function middleware(req: NextRequest) {
    const url = req.nextUrl.clone()

    if (/\.(.*)$/.test(url.pathname) || url.pathname.includes('_next')) return

    const host = req.headers.get('host')
    const subdomain = getSubdomain(host)
    if (subdomain) {
        url.pathname = `/${subdomain}${url.pathname}`
    }

    return NextResponse.rewrite(url)
}

I am aware I can use a custom server for this, but I'd rather avoid that to keep the app clean and scalable.

dragonmnl
  • 14,578
  • 33
  • 84
  • 129

0 Answers0