eduardweb.
DeploymentIntermediar#seo#nextjs#app-router#metadata

Cum am rezolvat SEO dinamic în Next.js: generateMetadata, OG Images și JSON-LD

De Florin Manea, 17 iul. 2026 · 15 vizualizări · 2 like-uri

Postat 17 iul. 2026
typescript
import { Metadata } from 'next';

interface Props {
  params: { id: string };
}

async function getProduct(id: string) {
  const res = await fetch(`https://api.exemplu.ro/products/${id}`);
  return res.json();
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const product = await getProduct(params.id);

  return {
    title: `${product.title} | Magazinul Nostru`,
    description: product.description,
    openGraph: {
      title: product.title,
      description: product.description,
      images: [
        {
          url: `https://api.exemplu.ro/og?id=${product.id}`,
          width: 1200,
          height: 630,
        },
      ],
    },
  };
}

Am trecut recent un magazin online destul de stufos de pe Pages Router pe App Router în Next.js și m-am lovit direct de noul mod de a gestiona SEO. Dacă te-ai săturat de vechiul <Head> și vrei metadate dinamice care chiar funcționează fără workaround-uri dubioase, generateMetadata e răspunsul. Vreau să îți arăt cum am structurat noi treaba asta pentru a menține un scor SEO de 100% fără să ruinăm performanța.

Cum funcționează generateMetadata și capcana performanței

În App Router, nu mai injectăm tag-uri manual. Folosim funcția exportată generateMetadata pentru pagini dinamice. La un proiect cu peste 12.000 de produse, primul meu instinct a fost să mă îngrijorez: dacă facem fetch la detalii în generateMetadata și apoi facem iar fetch în componenta paginii, nu dublăm timpul de încărcare?

Aici intervine logica din Next.js. Framework-ul face deduplicare automată prin fetch. Dacă apelezi exact același endpoint cu aceiași parametri în ambele locuri, baza de date e interogată o singură dată. Am obținut un TTFB cu 120ms mai rapid după ce am curățat vechile apeluri redundante de API.

Totuși, există un trade-off destul de mare. Dacă API-ul tău extern răspunde greu, generateMetadata va bloca complet randarea paginii (server-side rendering). Utilizatorul va vedea un ecran alb mai mult timp. Soluția mea a fost să folosesc un timeout agresiv pe fetch-ul din metadate sau să am un fallback static pregătit.

Imaginile Open Graph dinamice pe bune

Generarea de imagini OG dinamice (cele care apar când dai share pe Slack sau Facebook) e adesea ignorată pentru că e greu de implementat. În Next.js, ai două variante mari. Ori folosești fișierul special opengraph-image.tsx în directorul rutei, ori definești URL-ul direct în generateMetadata.

Am testat ambele variante. Pentru pagini simple de blog, opengraph-image.tsx e excelent pentru că rulează @vercel/og sub capotă. Dar pentru e-commerce, unde aveam nevoie de branding diferit per categorie și watermark-uri dinamice pe pozele de produs, a fost mult mai simplu să generez URL-urile direct în obiectul de metadate, trimițând ID-ul produsului către un serviciu extern de procesare imagini.

Structured Data (JSON-LD) fără bătăi de cap

Aici e o chestie pe care mulți o greșesc. API-ul de metadate din Next.js nu gestionează JSON-LD în mod nativ direct în obiectul returnat. Cea mai curată metodă recomandată chiar și de echipa Next.js este să injectezi un tag <script> direct în componenta paginii tale.

Nu te complica să pui schema.org în metadate. Aruncă un script de tip application/ld+json direct în componenta de Server din page.tsx. React știe să facă hoist la script-urile de acest gen în head-ul documentului fără să strice hidratarea pe client.

Tu ce folosești pentru generarea imaginilor de share? Rămâi pe varianta nativă cu opengraph-image sau preferi un serviciu extern gen Cloudinary?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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