Next.js
2. Metadata API (SEO basic)
On this page
page.tsx/layout.tsx can export metadata (title, description, Open Graph...) so that Next.js automatically injects it into the <head>. A natural question for detail pages (products, articles) is: is static metadata declaration sufficient, or is dynamic data fetching required, and if both page content and metadata require the exact same data, does this trigger duplicate API/DB calls?
1. metadata (static) vs. generateMetadata() (dynamic)
export const metadata = {...}: a static object declared at build/code time that cannot beawaited, suited for pages requiring no dynamic data (home, about).generateMetadata(): an async function receivingparams(dynamic segments from the URL) that canawaitinternal API/DB calls. Required for pages needing dynamic data to generate precise titles/descriptions (e.g. a product detail page where the product name is fetched from the DB).
tsx
export async function generateMetadata({ params }: { params: { id: string } }) {
const product = await fetchProduct(params.id);
return {
title: `${product.name} - ABC Store`,
description: product.description,
};
}
2. Preventing duplicate API/DB calls between page.tsx and generateMetadata()
- If both
page.tsx(rendering content) andgenerateMetadata()(generating titles) callfetchProduct(id), Next.js automatically dedupes them (Request Memoization): two identicalfetch()calls within the same request lifecycle trigger the underlying network request only once and share the result. - This is not a persistent cache (like Redis, which spans across requests) but a temporary per-request in-memory cache that is cleared after the request finishes.
- Only works automatically with native
fetch(). If accessing Prisma/ORMs directly (db.product.findUnique(...), common among backend developers) instead offetch(), Next.js does not deduplicate automatically. You must manually wrap the query using React'scache():
tsx
import { cache } from 'react';
const getProduct = cache(async (id: string) => {
return db.product.findUnique({ where: { id } });
});
// calling getProduct(id) in both page.tsx and generateMetadata() queries the DB only once
- Critical takeaway: this is an easily overlooked pitfall for developers accustomed to using Prisma directly instead of
fetch().
