eduardweb.
DeploymentIntermediar#performance#seo#nextjs#metadata

Cum optimizezi dynamic metadata și JSON-LD în Next.js fără să blochezi streaming-ul

De Andreea Crăciun, 1 sept. 2026 · 23 vizualizări · 2 like-uri

Postat 1 sept. 2026
typescript
import { cache } from 'react';
import type { Metadata } from 'next';

// Memoizare pentru ORM / apeluri DB non-fetch
const getProduct = cache(async (id: string) => {
  return db.product.findUnique({ where: { id } });
});

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

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

  if (!product) return { title: 'Produs negăsit' };

  return {
    title: `${product.name} | Magazinul Nostru`,
    description: product.summary,
    openGraph: {
      title: product.name,
      description: product.summary,
      images: [{ url: product.featuredImageUrl }],
    },
  };
}

export default async function ProductPage({ params }: Props) {
  const { id } = await params;
  const product = await getProduct(id);

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

  return (
    <article>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <h1>{product?.name}</h1>
    </article>
  );
}

La o migrare recentă pentru un magazin online cu vreo 45.000 de produse, SEO-ul era viața clientului. Dacă pierdeam indexările pe Google sau preview-urile pe WhatsApp și Slack crăpau, aveam o problemă serioasă pe cap.

În App Router, Metadata API rezolvă elegant problema meta tag-urilor dinamice, dar dacă nu ești atent la câteva detalii de execuție, riști să dublezi timpii de răspuns (TTFB) sau să faci apeluri redundante către backend.

generateMetadata și capcana apelurilor duplicate

Cea mai mare frică a mea la început a fost: dacă fac fetch la datele produsului în generateMetadata și încă o dată în Server Component-ul paginii, nu dublez numărul de query-uri?

Răspunsul scurt: nu, dacă folosești fetch nativ din Next.js, fiindcă face memoization automat la nivel de request lifecycle. Dacă tragi datele direct dintr-un ORM (cum ar fi Prisma sau Drizzle), Next.js nu știe să dedubleze apelul direct. Aici trebuie neapărat să înfășori funcția de query în React.cache().

Al doilea aspect: nu băga logică grea în generateMetadata. Orice await din această funcție blochează trimiterea primilor octeți către browser (<head>-ul trebuie calculat înainte ca streaming-ul HTML să înceapă). Extrage strict ce ai nevoie pentru titlu, descriere și imaginea de share.

metadataBase și Open Graph fără URL-uri hardcodate

Câte preview-uri pe rețele sociale n-am văzut sparte doar pentru că lipsea domeniul absolut din URL-ul imaginii de OG. În Next.js, setezi o singură dată metadataBase în layout-ul rădăcină (app/layout.tsx), iar apoi toate căile relative din paginile copil vor fi rezolvate corect:

export const metadata = {
  metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || 'https://site-ul-tau.ro'),
};

Când generezi imagini OG dinamice folosind fișiere opengraph-image.tsx (cu @vercel/og), Next.js le leagă automat și le injectează în meta tag-uri, fără să le mai declari manual.

Unde punem JSON-LD pentru Structured Data?

Tipul Metadata din Next.js nu suportă nativ un nod dedicat pentru schema.org sau script-uri arbitrare de JSON-LD. Cea mai curată abordare pe care am testat-o în producție este să injectezi tag-ul <script type="application/ld+json"> direct în JSX-ul componentei de pagină (Server Component).

Browserul și crawlerii Google îl parsează instant din HTML-ul server-rendered, fără niciun impact negativ asupra performanței.

Trade-off sincer

Sistemul e impecabil pentru aplicații content-heavy și e-commerce unde ai mii de pagini dinamice. În schimb, dacă ai un dashboard privat în spatele unui login unde SEO nu contează deloc, generateMetadata adaugă boilerplate inutil — acolo e mai eficient să lași un titlu generic static în layout și să nu-ți bați capul.

Voi cum gestionați generarea imaginilor de OG pentru mii de pagini: le generați on-the-fly cu Edge functions sau preferați să le generați la build time pe S3/Cloudinary?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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