How to Add Structured Data to Your Next.js App (JSON-LD Guide)
Structured data (JSON-LD) tells Google what your page is about โ enabling rich results like FAQ dropdowns, star ratings, event dates, and article bylines directly in search results. Here's how to add it correctly in Next.js 14+ App Router.
The pattern: script tag with dangerouslySetInnerHTML
JSON-LD goes inside a <script type="application/ld+json"> tag. In the Next.js App Router, place it directly in your page or layout component:
// app/page.tsx (or any page/layout)
export default function Page() {
const jsonLd = {
"@context": "https://schema.org",
"@type": "WebSite",
name: "Your Site",
url: "https://yoursite.com",
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{/* rest of your page */}
</>
)
}FAQPage schema (most useful for SEO)
const faqLd = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqItems.map(({ q, a }) => ({
"@type": "Question",
name: q,
acceptedAnswer: { "@type": "Answer", text: a },
})),
}FAQPage schema can double your SERP real estate by showing expandable Q&A directly under your search result. It works best on pages that already have visible FAQ content.
Article schema for blog posts
// app/blog/[slug]/page.tsx
const articleLd = {
"@context": "https://schema.org",
"@type": "Article",
headline: post.title,
description: post.description,
url: `https://yoursite.com/blog/${post.slug}`,
datePublished: post.date,
dateModified: post.updatedAt ?? post.date,
author: { "@type": "Person", name: "Your Name" },
publisher: {
"@type": "Organization",
name: "Your Site",
logo: { "@type": "ImageObject", url: "https://yoursite.com/logo.png" },
},
}BreadcrumbList (improves site structure signals)
const breadcrumbLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{ "@type": "ListItem", position: 1, name: "Home", item: "https://yoursite.com" },
{ "@type": "ListItem", position: 2, name: "Blog", item: "https://yoursite.com/blog" },
{ "@type": "ListItem", position: 3, name: post.title, item: `https://yoursite.com/blog/${post.slug}` },
],
}Multiple schemas on one page
You can โ and should โ include multiple JSON-LD blocks on a single page. Each gets its own <script> tag:
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(articleLd) }} />
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }} />
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqLd) }} />
{/* page content */}
</>
)Validation
After deploying, test your structured data at search.google.com/test/rich-results. It shows exactly which rich results your page is eligible for and flags any missing required fields.
To generate the JSON-LD without writing it by hand, use the Schema.org JSON-LD Generator โ free, no account required.
Try the related tool
Schema.org JSON-LD Generator โ free, runs 100% in your browser.
Open Schema.org JSON-LD Generator โEnjoyed this? Get notified when Pro launches.
