Next.js SEO
How to Add JSON-LD in Next.js: Article, Product, Software, and Breadcrumb Schema
Add safe, accurate JSON-LD to Next.js App Router pages with Article, Product, SoftwareApplication, and BreadcrumbList examples.
Structured data should be a typed projection of the page users can see. It is not a second marketing channel where missing facts can be filled with optimistic guesses.
Choose the entity before the schema
Ask what the page primarily represents. A news or blog post may be an Article. A purchasable item may be a Product with an Offer. A software landing page may describe a SoftwareApplication. BreadcrumbList describes navigation hierarchy and can accompany another primary entity.
Do not select a type because its search appearance looks attractive. Search features have eligibility rules beyond valid JSON, and displaying markup does not guarantee a rich result. The first goal is an accurate machine-readable description that stays aligned with the visible page.
Render JSON-LD on the server
Build the object in a Server Component using the same record that renders the page. Serialize it into a script with type application/ld+json. Replace less-than characters in the serialized value so user-controlled strings cannot close the script element and inject markup.
Keep the helper small. It should serialize data safely, not decide business facts. Construct Article, Product, or SoftwareApplication objects in typed functions that can validate required fields and omit unknown optional values.
export function JsonLd({ data }) {
const json = JSON.stringify(data).replaceAll("<", "\u003c");
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: json }}
/>
);
}Describe an article
Use the canonical headline, description, publication and modification dates, author, publisher, primary image, and main page URL. Update dateModified only for a substantive change to the article. A site-wide rebuild is not an editorial revision.
The author should match the visible byline. If the page credits an organization, mark up the organization; if it credits a person, use that person. Link to stable author or publisher pages when available and keep the logo URL absolute.
const article = {
"@context": "https://schema.org",
"@type": "Article",
headline: post.title,
description: post.excerpt,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
mainEntityOfPage: SITE_URL + "/blog/" + post.slug,
author: { "@type": "Organization", name: "Acme" },
};Describe a purchasable product
Product data can include the name, description, images, SKU, brand, and offers. Offer values such as price, currency, URL, condition, and availability must match what a shopper can see and buy. Generate them from the same commerce record used by the page.
Variants require a clear model. Do not emit several contradictory prices as one offer without explaining the range, and do not claim InStock when the checkout path rejects the item. Reviews and aggregate ratings must come from real visible review data and follow the relevant search policies.
const product = {
"@context": "https://schema.org",
"@type": "Product",
name: item.name,
image: item.images,
sku: item.sku,
offers: {
"@type": "Offer",
price: item.price.amount,
priceCurrency: item.price.currency,
availability: item.inStock
? "https://schema.org/InStock"
: "https://schema.org/OutOfStock",
},
};Describe a SaaS application honestly
SoftwareApplication can identify the application name, category, operating system, URL, and description. Add an Offer only when the price and terms correspond to a visible option. If pricing varies or requires contact, represent that accurately rather than forcing a misleading zero-price offer.
Structured data cannot replace a clear product page. The visible page still needs to explain the job, audience, features, constraints, pricing path, and next action. Keep claims such as ratings or awards out unless the page and evidence support them.
Validate data and failure behavior
Validate the JSON syntax, schema shape, and search-feature requirements, then compare every material value with the visible page. Test quotes, angle brackets, Unicode, missing images, no price, out-of-stock products, unpublished articles, and changed canonical URLs.
A missing optional field should usually omit the property. A missing required business fact may mean the page is not ready for that schema. Log validation failures during development and content ingestion rather than serving invented defaults.
Verify structured data on the promoted route
Adios lets the same Next.js release serve the visible page and JSON-LD from one persistent runtime. Deploy the candidate, fetch the generated route, and validate the script from the actual HTML. Build logs expose serialization or type failures; runtime logs help trace records that fail only with production data.
After the health check succeeds, keep the custom domain and managed TLS attached to the promoted version. Re-run validation against the canonical URL because host, redirects, environment values, and image URLs can differ from a local test.
env:
NEXT_PUBLIC_SITE_URL: https://www.example.com
runtime:
name: node@24
port: 3000
health_path: /api/health