August 24, 2026
2 min read
A few hundred bytes of JSON-LD per page decides whether a result shows an author, a date, and breadcrumbs. The BlogPosting payload, how to render it safely in next/head, and how to validate it.
Structured data tells search engines what a page actually contains — an article, its author, its publish date — instead of leaving them to infer it from markup. In Google it is what makes a result eligible for rich treatment: the author line, the date, the breadcrumb trail. The format Google recommends is JSON-LD, placed inside a script tag in the page head.
For a blog, three schema types cover most of the value:
BlogPosting on each articleBreadcrumbList on any nested pagePerson or Organization once, for the site ownerfunction articleJsonLd(post: Post) {
return {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
datePublished: post.createdAt,
dateModified: post.updatedAt,
author: { '@type': 'Person', name: 'Your Name' },
mainEntityOfPage: https://example.com/blog/${post.slug},
};
}
In the Pages Router, render it inside next/head. Serialize with a helper that escapes any opening angle bracket in the JSON string, so a value containing markup cannot terminate the script tag early:
// escape "<" as its unicode form before injecting
const toSafeJson = (data: object) =>
JSON.stringify(data).replaceAll('<', String.fromCodePoint(0x5c) + 'u003c');
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: toSafeJson(articleJsonLd(post)) }}
/>
</Head>
In the App Router, render the same script tag directly in the server component.
2026-08-24T11:35:00Z)headline longer than 110 characters — Google truncates itA few hundred bytes of JSON-LD per page is one of the highest-leverage SEO changes for a blog: cheap to add, easy to validate, and it directly affects how results are displayed.