Next.js hreflang

Next.js hreflang: implement language alternatives in the App Router

A practical guide to locale routes, reciprocal hreflang links, translated metadata, and dynamic pages in a Next.js App Router application.

/ The short answer

Hreflang works when every language version has its own crawlable URL, identifies the complete language set, and links back to the other versions. In Next.js, generate those relationships with route-aware metadata instead of relying on browser language detection alone.

/ 01

Start with URLs

Give every language version a stable route

Use a route structure such as /fr/pricing or /de/products/widget. The page should be reachable directly, render the matching language on the server, and remain valid when a crawler requests it without browser cookies or an Accept-Language preference.

  • Keep one canonical URL per language version.
  • Use stable slugs or a documented localized-slug strategy for dynamic pages.
  • Return a real 200 response for every published language route.
App Router route shape
app/
  [locale]/
    products/
      [slug]/
        page.js
        opengraph-image.js
    layout.js
    sitemap.js

// /fr/products/widget
// /de/products/widget
/ 02

Generate metadata

Create reciprocal language relationships

Next.js metadata supports an alternates.languages object. Generate the same complete language set from each locale page so the English, French, and German versions all point to one another.

  • Include the current page in its own language map.
  • Use fully qualified HTTPS URLs in production.
  • Keep language codes consistent with the locale values used by your application.
generateMetadata with Altified
import { headers } from "next/headers";
import { altified } from "@/lib/altified";

export async function generateMetadata() {
  const locale = (await headers()).get("x-altified-locale") || "en";

  return altified.translatedMetadata({
    locale,
    path: "/pricing",
    origin: "https://example.com",
    locales: ["en", "fr", "de"],
    title: "Pricing",
    description: "Plans for your product.",
  });
}
/ 03

Render the content

Make the page language match the URL

Hreflang is not a translation mechanism. The page at /fr/products/widget must actually render French content, metadata, navigation, structured data, and relevant dynamic values. Resolve the active locale before the response reaches the browser.

  • Translate titles, descriptions, Open Graph fields, and visible headings together.
  • Forward the active locale to backend APIs.
  • Use source-language fallbacks while a translation is pending.
Forward the active locale
const response = await altifiedFetch(BACKEND_URL + path);

// The active Altified locale is forwarded to the backend.
const product = await response.json();
/ 04

Validate the cluster

Check both directions before launch

Search engines can ignore incomplete or contradictory language clusters. Test every published language page, inspect its rendered head, and confirm that the links are reciprocal and that each page has a self-canonical URL.

  • English points to French, German, and English.
  • French points to English, German, and French.
  • Each canonical uses the same language as the page content.
  • Unpublished or incomplete locales are not advertised as live alternatives.

/ Production checklist

Verify the language experience before launch.

  • Every locale has a direct, crawlable URL.
  • Every language page returns translated content and metadata.
  • Hreflang links are reciprocal.
  • Canonicals are self-referential in the page language.
  • Dynamic product and article routes are included.
  • The site sitemap contains the language URL set.

/ Frequently asked questions

Questions teams ask before implementing multilingual SEO.

Does Next.js generate hreflang automatically?

Next.js provides metadata APIs for language alternates, but your application must supply the correct locale URLs and language mapping.

Should hreflang URLs be absolute?

Use fully qualified HTTPS URLs in production metadata and sitemaps so the language relationships are unambiguous.

Do I still need canonical tags when using hreflang?

Yes. Hreflang describes equivalent language or regional versions; each localized page should still identify its own canonical URL.