Tools: Adding structured data to a Next.js site without losing your mind:

Tools: Adding structured data to a Next.js site without losing your mind:

Source: Dev.to

The problem with JSON-LD ## Component approach ## The validation loop ## One gotcha that cost me hours ## Results Google's rich results look great in search. Getting them? Not so great. I recently added structured data to a Next.js project and learned a few things the hard way. Schema.org documentation is... extensive. Too extensive. You'll find 800+ types and wonder which 3 you actually need. For most content sites, it's: That's it. Ignore the rest until Google tells you otherwise. Instead of dumping JSON-LD strings everywhere, I created typed React components: TypeScript catches missing fields before Google does. Here's the workflow that actually works: Don't skip step 2. Localhost testing misses URL-related issues. Dynamic dates in schema must be ISO 8601 format: Google's validator gives cryptic errors for this. Now you know. After implementing structured data on a small product review site, FAQ rich results started appearing within 2 weeks. No guarantees—Google decides—but eligibility is the first step. The full schema setup took about 4 hours. Most of that was reading documentation I didn't need. What structured data types are you using? I'm curious if anyone's had luck with HowTo or Recipe schemas. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: // components/seo/ArticleSchema.tsx export function ArticleSchema({ post }: { post: BlogPost }) { const schema = { "@context": "https://schema.org", "@type": "Article", headline: post.title, datePublished: post.publishedAt, author: { "@type": "Person", name: post.author.name } }; return ( <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} /> ); } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: // components/seo/ArticleSchema.tsx export function ArticleSchema({ post }: { post: BlogPost }) { const schema = { "@context": "https://schema.org", "@type": "Article", headline: post.title, datePublished: post.publishedAt, author: { "@type": "Person", name: post.author.name } }; return ( <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} /> ); } CODE_BLOCK: // components/seo/ArticleSchema.tsx export function ArticleSchema({ post }: { post: BlogPost }) { const schema = { "@context": "https://schema.org", "@type": "Article", headline: post.title, datePublished: post.publishedAt, author: { "@type": "Person", name: post.author.name } }; return ( <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }} /> ); } CODE_BLOCK: // Wrong - breaks validation datePublished: new Date().toLocaleDateString() // Right datePublished: new Date().toISOString() Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: // Wrong - breaks validation datePublished: new Date().toLocaleDateString() // Right datePublished: new Date().toISOString() CODE_BLOCK: // Wrong - breaks validation datePublished: new Date().toLocaleDateString() // Right datePublished: new Date().toISOString() - Organization (who you are) - WebSite (with SearchAction for sitelinks) - Article or Product (your actual content) - BreadcrumbList (navigation context) - Add schema component to page - Deploy (or use next build && next start) - Test with Google's Rich Results Test - Fix warnings