Next.js Discord

Discord Forum

Dynamically generate sitemap.xml

Answered
Giant panda posted this in #help-forum
Open in Discord
Giant pandaOP
Can I not have a folder called sitemap.xml and a route.ts inside of it?
If the folder is called sitemap (without .xml) the route.ts works. However, if it's with the .xml it gives a 404
Also, this (https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-sitemap) is not enough, as it seems to only work in the root directory. I have a multi-tenant application, so I need multiple sitemaps
Answered by joulev
yes definitely, see that \.\w+? that matches the .xml
View full answer

32 Replies

Ocicat
hey @Giant panda there is no NextResponse.xml() in the route configuration:

https://nextjs.org/docs/app/api-reference/functions/next-response#json

If it was then I guess this would be possible.
@Ocicat hey <@131537558453747712> there is no `NextResponse.xml()` in the route configuration: https://nextjs.org/docs/app/api-reference/functions/next-response#json If it was then I guess this would be possible.
Giant pandaOP
I think you misunderstand - The route won't even trigger a console.log. It's not about returning a response
@Ocicat hey <@131537558453747712> there is no `NextResponse.xml()` in the route configuration: https://nextjs.org/docs/app/api-reference/functions/next-response#json If it was then I guess this would be possible.
Giant pandaOP
I wouldn't need a NextResponse.xml, I can just return it like so:
  return `<?xml version="1.0" encoding="UTF-8"?>
   <urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
     <!--We manually set the two URLs we know already-->
     <url>
       <loc>${URL}</loc>
     </url>
     <url>
       <loc>${URL}</loc>
     </url>
      <url>
       <loc>${URL}</loc>
     </url>
     ${posts
       .map(({ id }) => {
         return `
           <url>
               <loc>${`${URL}/${id}`}</loc>
           </url>
         `
       })
       .join('')}
   </urlset>
 `
}
:SW_Shrug:
Ocicat
what is the encoding of this? is it text/xml?
you could check by inspecting the response headers
dont even need to check the encoding; simon said a route containing sitemap.xml cannot work on his machine so i demonstrated by making a route containing sitemap.xml work just like intended
if you want text/xml you can always add the headers
@Giant panda https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-sitemap Does this also work in non-root folders for you joulev?
haven't checked but idt i need to
@joulev haven't checked but idt i need to
Giant pandaOP
Ah
yes, the root is bold so...
Giant pandaOP
Sad
anyway just make a route handler that returns the sitemap.xml content with text/xml...
it works fine
Giant pandaOP
I don't see anything sus in my middleware that would prevent me from having .xml in a route
export default withClerkMiddleware((req: NextRequest) => {
  const url = req.nextUrl

  // Get hostname of request (e.g. demo.vercel.pub, demo.localhost:3000)
  const hostname = req.headers.get('host') || 'demo.useverk.com'

  // Get the pathname of the request (e.g. /, /about, /blog/first-post)
  const path = url.pathname

  if (path.startsWith('/api')) {
    return NextResponse.next()
  }

  const currentHost =
    // eslint-disable-next-line turbo/no-undeclared-env-vars
    process.env.NODE_ENV === 'production' && process.env.VERCEL === '1'
      ? hostname.replace(`.useverk.com`, '')
      : hostname.replace(`.localhost:3000`, '')

  // rewrites for app pages
  if (currentHost == 'app') {
    if (isPublic(req.nextUrl.pathname)) {
      url.pathname = `/app${url.pathname}`
      return NextResponse.rewrite(url)
    }

    const { userId } = getAuth(req)

    if (!userId) {
      const signInUrl = new URL('/sign-in', req.url)
      signInUrl.searchParams.set('redirect_url', req.url)
      return NextResponse.redirect(signInUrl)
    }
    url.pathname = `/app${url.pathname}`
    return NextResponse.rewrite(url)
  }

  // rewrite root application to `/home` folder
  if (
    hostname === 'localhost:3000' ||
    hostname === 'useverk.com' ||
    hostname === 'www.useverk.com' ||
    hostname === 'www2.useverk.com' ||
    hostname.endsWith('vercel.app')
  ) {
    return NextResponse.rewrite(new URL(`/home${path}`, req.url))
  }

  // rewrite everything else to `/_sites/[site] dynamic route
  return NextResponse.rewrite(
    new URL(`/sites/${currentHost}${path}${req.nextUrl.search}`, req.nextUrl)
  )
})
@Giant panda I don't see anything sus in my middleware that would prevent me from having .xml in a route ts export default withClerkMiddleware((req: NextRequest) => { const url = req.nextUrl // Get hostname of request (e.g. demo.vercel.pub, demo.localhost:3000) const hostname = req.headers.get('host') || 'demo.useverk.com' // Get the pathname of the request (e.g. /, /about, /blog/first-post) const path = url.pathname if (path.startsWith('/api')) { return NextResponse.next() } const currentHost = // eslint-disable-next-line turbo/no-undeclared-env-vars process.env.NODE_ENV === 'production' && process.env.VERCEL === '1' ? hostname.replace(`.useverk.com`, '') : hostname.replace(`.localhost:3000`, '') // rewrites for app pages if (currentHost == 'app') { if (isPublic(req.nextUrl.pathname)) { url.pathname = `/app${url.pathname}` return NextResponse.rewrite(url) } const { userId } = getAuth(req) if (!userId) { const signInUrl = new URL('/sign-in', req.url) signInUrl.searchParams.set('redirect_url', req.url) return NextResponse.redirect(signInUrl) } url.pathname = `/app${url.pathname}` return NextResponse.rewrite(url) } // rewrite root application to `/home` folder if ( hostname === 'localhost:3000' || hostname === 'useverk.com' || hostname === 'www.useverk.com' || hostname === 'www2.useverk.com' || hostname.endsWith('vercel.app') ) { return NextResponse.rewrite(new URL(`/home${path}`, req.url)) } // rewrite everything else to `/_sites/[site] dynamic route return NextResponse.rewrite( new URL(`/sites/${currentHost}${path}${req.nextUrl.search}`, req.nextUrl) ) })
does removing it fix the problem?
you have to confirm that middleware is the cause first before debugging it
@joulev does removing it fix the problem?
Giant pandaOP
Can't remove the middleware - Debugging on demo.localhost:3000 - Which this part handles:
But I'll try debugging in some other ways, appreciate it
// rewrite everything else to `/_sites/[site] dynamic route
  return NextResponse.rewrite(
    new URL(`/sites/${currentHost}${path}${req.nextUrl.search}`, req.nextUrl)
  )
just suggesting in case it is not a middleware bug so you could be wasting time debugging it
Giant pandaOP
Right, yeah, I'll give it a go
Yeah, it did
That works
well... good luck debugging the middleware then
you might have to report this to the clerk team
@joulev well... good luck debugging the middleware then
Giant pandaOP
Yeah, middleware is not even triggering. I suspect it has something to do with my matcher config though '/((?!_next/|_static/|examples/|[\w-]+\.\w+).*)',
Answer