eduardweb.
DeploymentIntermediar#seo#nextjs#typescript#react#metadata

Metadata API în Next.js 16: Dynamic SEO, OG Images și JSON-LD fără bătăi de cap

De Răzvan Matei, 11 aug. 2026 · 6 vizualizări · 3 like-uri

Postat acum 5 zile
typescript
import type { Metadata, ResolvingMetadata } from 'next';

type Props = {
  params: Promise<{ slug: string }>;
};

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const { slug } = await params;
  
  const product = await fetch(`https://api.site.ro/products/${slug}`, {
    next: { revalidate: 3600 }
  }).then((res) => res.json());

  const previousImages = (await parent).openGraph?.images || [];

  return {
    title: `${product.title} | MagazinOnline`,
    description: product.summary,
    openGraph: {
      title: product.title,
      description: product.summary,
      images: [`/api/og?title=${encodeURIComponent(product.title)}`, ...previousImages],
    },
    alternates: {
      canonical: `https://site.ro/produse/${product.slug}`,
    },
  };
}

export default async function ProductPage({ params }: Props) {
  const { slug } = await params;
  const product = await fetch(`https://api.site.ro/products/${slug}`).then((res) => res.json());

  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'Product',
    name: product.title,
    description: product.summary,
    image: product.image,
  };

  return (
    <section>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <h1>{product.title}</h1>
      <p>{product.summary}</p>
    </section>
  );
}

Am refăcut recent arhitectura de SEO pentru un shop cu peste 35.000 de produse și ne loveam de o problemă veche: cum generezi meta tags dinamice, Open Graph personalizat pentru social media și date structurate JSON-LD fără să distrugi timpul de răspuns al serverului. În Next.js 16, API-ul nativ de Metadata rezolvă elegant problema, dar dacă nu ești atent la caching, poți îngreuna grav TTFB-ul.

Nu mai avem nevoie de librării terțe sau hack-uri cu next/head. Totul e mutat pe Server Components, ceea ce e grozav pentru securitate și bundle size.

De la head tags la generateMetadata

Trecerea la App Router a schimbat complet paradigma. În loc să injectezi tag-uri direct în DOM-ul virtual la nivel de client, folosești funcția exportată generateMetadata. Un detaliu super important pe care mulți îl ratează la trecerea pe versiunile recente de Next.js: params și searchParams sunt acum de tip Promise și trebuie rezolvate cu await înainte de a fi folosite.

Dacă ai apeluri de date similare atât în pagină cât și în generateMetadata, React le deduplică automat prin mecanismul de fetch memoization. Practic, nu faci două request-uri la baza de date pentru același produs, deși codul arată așa.

Caching și trade-off-ul de latență

Aici e punctul unde mulți își fură singuri căciula. generateMetadata blochează stream-ul de HTML până când promise-ul e rezolvat. Am avut cazul la un client unde un API extern de CMS răspundea în 450ms. Pagina întreagă stătea blocată 450ms doar pentru a citi titlul și descrierea din meta-uri.

Trade-off-ul e simplu: câștigi un SEO impecabil și dinamic, dar dacă API-ul tău de backend sughite, suferă și utilizatorul real. Soluția pe care am aplicat-o a fost un caching agresiv la nivel de fetch (revalidate: 3600) și fallback-uri statice pe atribute generale când serviciul de date e indisponibil.

OG Images și Structured Data JSON-LD

Pentru Open Graph dinamice, pachetul @vercel/og integrat prin ImageResponse e absolut genial. Generezi o imagine JSX la zbor, pe Edge. Însă mare atenție la consumul de resurse: pe un volum de 12.000 de cereri pe oră, generarea continuă de imagini SVG/PNG poate consuma serios din cota de serverless/lambda.

Cât despre JSON-LD (Schema.org), uitați de pachete de npm care adaugă 20kb în plus. Cea mai curată metodă este să injectezi un script tag cu dangerouslySetInnerHTML bezpośrednio în layout sau pagină. Next.js știe să îl sanitizeze corect dacă e codificat JSON valid.

Voi ce abordare folosiți pentru paginile cu date care se schimbă la câteva secunde? Rămâneți pe revalidare la cerere sau folosiți meadată generică cu fallback-uri?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.