De App Router heeft next/head vervangen door een getypeerde Metadata API. Twee manieren om haar te gebruiken: een statische export voor vaste pagina's, generateMetadata voor dynamische:
// app/layout.tsx — standaardinstellingen voor de hele site met een titelsjabloon
import type { Metadata } from "next";
export const metadata: Metadata = {
metadataBase: new URL("https://example.com"),
title: {
template: "%s | Acme",
default: "Acme — webdevelopmentstudio",
},
description: "Standaardbeschrijving, gebruikt wanneer een pagina er geen eigen instelt.",
};
// app/blog/[slug]/page.tsx — dynamische metadata per post
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
if (!post) return { title: "Bericht niet gevonden" };
return {
title: post.title, // via het sjabloon wordt dit "Titel van het bericht | Acme"
description: post.excerpt,
};
}
Praktische regels die echt invloed hebben op posities:
- Title: ~50–60 tekens, het belangrijkste zoekwoord dicht bij het begin, uniek voor elke pagina. Google herschrijft zwakke titels, dus geef hem geen reden.
- Description: ~150–160 tekens. Heeft geen directe invloed op de ranking, maar is je advertentietekst in de resultaten en stuurt de CTR aan.
metadataBaseis verplicht: zonder die waarde breken relatieve adressen van OG-afbeeldingen en canonicals in productie.- Ontdubbel de query tussen
generateMetadataen de paginacomponent met Reactcache(), anders vraag je het CMS twee keer per request aan.
import { cache } from "react";
export const getPost = cache(async (slug: string) => {
return fetchPostFromCMS(slug);
});
Checklist:
-
metadataBaseingesteld in de root-layout - Titelsjabloon één keer gedefinieerd, pagina's zetten alleen hun eigen deel
- Elke pagina heeft een unieke title en description
- CMS-pagina's gebruiken
generateMetadatamet een fetch verpakt incache() - Terugvalmetadata voor 404 / ontbrekende content
