Search code examples
next.jsmultilingualsitemapapp-router

Next.js 14 Sitemap generation with multilanguage


My site on Next.js 14 (App Router) has multi-language support and needs to generate sitemap.xml with:

<xhtml:link rel="alternate" hreflang="YOUR_LOCALE" href="YOUR_LINK" />

as Google shows in the following example: https://developers.google.com/search/docs/specialty/international/localized-versions#sitemap

How is it possible to do this?

In Next.js 14 (App Router) sitemap generation you can only specify 4 parameters that have nothing to do with localization: https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap

Or you can write sitemap.xml manually, but the site has product pages that are more than 2000 and manually doing it is crazy.

Maybe there is a way to build a string yourself? (getServerSideProps - not supported in App Router)

UPD: Thanks for solution Andrii Bodnar

Before the solution was worked out through the use of Route Handlers, where I returned the content as in sitemap.xml. Each folder with route.ts was named “sitemap.xml”. If dynamic routing was needed, it was just inside the folder, e.g. “[id]” - put the folder “sitemap.xml” with route.ts inside. For clarity, the structure is as follows:

.
└── sitemap.xml/
    ├── products/
    │   ├── [id]/
    │   │   └── sitemap.xml/
    │   │       └── route.ts
    │   └── sitemap.xml/
    │       └── route.ts
    └── route.ts

Solution

  • Version 14.2 of Next.js has been released. This version includes a lot of great features and improvements, including the localized Sitemap generation.

    Now you can generate a localized sitemap as follows:

    import { MetadataRoute } from 'next'
     
    export default function sitemap(): MetadataRoute.Sitemap {
      return [
        {
          url: 'https://acme.com',
          lastModified: new Date(),
          alternates: {
            languages: {
              es: 'https://acme.com/es',
              de: 'https://acme.com/de',
            },
          },
        },
        {
          url: 'https://acme.com/about',
          lastModified: new Date(),
          alternates: {
            languages: {
              es: 'https://acme.com/es/about',
              de: 'https://acme.com/de/about',
            },
          },
        },
      ]
    }
    

    Visit the official documentation for more details.