aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webontwikkeling

Next.js SEO: titel, OG en canonical met de Metadata API

Als mensen het over Next.js SEO hebben, denken ze eerst aan het correct vullen van de <head> van de pagina: een betekenisvolle titel, een beschrijvende description, Open Graph-tags voor sociaal delen en een canonical link die dubbele content voorkomt. De Metadata API die met de App Router meekomt, laat je dit allemaal doen zonder zelf <head>-elementen te schrijven, op een type-veilige manier die op de server wordt opgelost. In deze gids loop ik door een praktische opzet, van het statische metadata-object tot de dynamische generateMetadata-functie.

Wat is de Metadata API?

In de App Router (Next.js 13.2 en later) kan elk layout.tsx- en page.tsx-bestand op twee manieren metadata exporteren: een metadata-object voor constante waarden, of een asynchrone generateMetadata-functie voor waarden die afhangen van het verzoek of van data. Next.js leest deze en genereert de <head> van de pagina voor je. Eén belangrijke regel: deze exports werken alleen in Server Component-bestanden; je kunt geen metadata exporteren uit een bestand met "use client".

Titel en description met statische metadata

De eenvoudigste vorm is het exporteren van een constant object. Meestal zet je een site-brede versie in de root app/layout.tsx en voeg je daarna pagina-specifieke versies per route toe.

// app/layout.tsx
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: {
    default: "aslain.dev — Web- & gameontwikkeling",
    template: "%s | aslain.dev",
  },
  description: "Gidsen over web, gameservers en Discord-botontwikkeling.",
};

Het veld title.template is een krachtig hulpmiddel: onderliggende pagina's geven alleen hun eigen titel, en Next.js plaatst die in %s en voegt de sitenaam toe. Als een pagina bijvoorbeeld title: "Contact" instelt, wordt de uitvoer Contact | aslain.dev. Je hoeft je merknaam niet meer in elke titel handmatig te herhalen.

Dynamische Next.js SEO met generateMetadata

Op routes waarvan de content uit een database komt — blogposts, productpagina's — moeten titel en description ook dynamisch zijn. Daar komt generateMetadata in beeld. Het ontvangt hetzelfde params-argument als de pagina zelf, haalt data op en retourneert metadata.

// app/blog/[slug]/page.tsx
import type { Metadata } from "next";

export async function generateMetadata(
  { params }: { params: Promise<{ slug: string }> }
): Promise<Metadata> {
  const { slug } = await params;
  const post = await getPost(slug);

  return {
    title: post.title,
    description: post.excerpt,
  };
}

In Next.js 15 werd params een Promise, dus je moet het met await oplossen. Een belangrijke prestatie-opmerking: fetch-aanroepen binnen generateMetadata worden door de request-memoization van Next.js gededupliceerd wanneer ze in hetzelfde paginacomponent worden herhaald, dus wees niet bang om dezelfde data twee keer op te halen.

Open Graph- en Twitter-kaarten

Hoe je link eruitziet wanneer hij wordt gedeeld op WhatsApp, X of LinkedIn, wordt bepaald door Open Graph-tags. De Metadata API stelt deze netjes beschikbaar onder de sleutels openGraph en twitter.

export const metadata: Metadata = {
  openGraph: {
    title: "Next.js SEO-gids",
    description: "Titel, OG en canonical met de Metadata API.",
    url: "https://aslain.dev/blog/nextjs-seo",
    siteName: "aslain.dev",
    images: [{ url: "/og/nextjs-seo.png", width: 1200, height: 630 }],
    locale: "nl_NL",
    type: "article",
  },
  twitter: {
    card: "summary_large_image",
    title: "Next.js SEO-gids",
    images: ["/og/nextjs-seo.png"],
  },
};
  • Afbeeldingsformaat: 1200×630 pixels is de standaardverhouding die sociale platforms verwachten.
  • type: "article": het juiste OG-type voor blogposts; gebruik "website" voor de homepage.
  • Als je de Twitter-kaart niet apart opgeeft, worden de meeste velden overgenomen van Open Graph; toch is het goed om het card-type expliciet in te stellen.

Canonical en taalalternatieven

Als dezelfde content via meerdere URL's bereikbaar is (een slash op het einde, trackingparameters), is een canonical tag essentieel om zoekmachines het gezaghebbende adres te vertellen. De Metadata API biedt deze onder alternates.

export const metadata: Metadata = {
  metadataBase: new URL("https://aslain.dev"),
  alternates: {
    canonical: "/blog/nextjs-seo",
    languages: {
      "nl-NL": "/nl/blog/nextjs-seo",
      "en-US": "/en/blog/nextjs-seo",
    },
  },
};

Definieer altijd metadataBase: relatieve paden (zoals /blog/... of /og/...) worden ten opzichte van deze basis tot absolute URL's herleid. Laat je dit weg, dan geeft Next.js tijdens de ontwikkeling een waarschuwing en verschijnen OG-afbeeldingen op sommige platforms mogelijk niet omdat ze geen absolute URL hebben. De alternatieven die je onder languages opsomt, worden hreflang-tags, wat meertalige SEO versterkt.

Veelgemaakte fouten

  • Exporteren vanuit een client-component: metadata exporteren uit een "use client"-bestand doet stilletjes niets; houd metadata in een Server Component.
  • metadataBase vergeten: OG-afbeeldingen en canonical breken omdat ze relatief blijven.
  • De titel twee keer definiëren: title en openGraph.title kunnen verschillen; houd je ze niet consistent, dan oogt het delen verwarrend.
  • Een handmatige <head> erbij mengen: schrijf in de App Router geen <head>-element met de hand — de Metadata API moet de enige bron van waarheid zijn.

Veelgestelde vragen

Moet ik het metadata-object of generateMetadata gebruiken?

Als de waarden constant zijn (statische pagina's, de root-layout), is het metadata-object eenvoudiger en sneller. Komt de titel of description uit data, params of het verzoek, gebruik dan generateMetadata. Exporteer beide niet vanuit hetzelfde bestand; Next.js staat dat niet toe.

Genereert de Metadata API ook sitemap- en robots-bestanden?

Ja. De bestanden app/sitemap.ts en app/robots.ts vallen onder de bestand-gebaseerde metadataconventies, en Next.js zet ze automatisch om naar de eindpunten /sitemap.xml en /robots.txt. Evenzo worden app/icon.png en app/opengraph-image.tsx herkend.

Vertraagt generateMetadata het laden van pagina's?

Meestal niet. De data-aanroepen gebruiken dezelfde cache als het paginacomponent (request-memoization), dus dezelfde fetch doet geen twee netwerkverzoeken. Vermijd toch onnodig zware queries en gebruik waar mogelijk cachebare gegevensbronnen.

Wil je de Next.js SEO-basis van je site vanaf nul opzetten, of je bestaande metadata laten controleren? Laten we de App Router-, Open Graph- en canonical-structuur rond jouw project bouwen — neem contact met me op.

Bu kategorideki tüm yazılar →

Devamı için