craigmadethis

Working With Structured Data in Next.js 14

Published: 15/02/2024, 22:00:00

Updated:17/02/2024, 23:20:00

The first time I worked with structured data I hated it. It's not especially difficult to implement in a nextjs project, it's actually just quite difficult to remember all the different schemas. So here's how I do it, so you too can forget what properties a MortgageLoan can have.

Note: All examples here are using the app directory in a Next 14 project. Things might change (they definitely will) and I'll try my best to keep them updated.

So firstly why structured data? Well I was building a site for Military Museum Scotland and I really wanted it to show up properly on Google. At the time of building the site there were a few events coming up, and I was keen to get them to show up on Google when locals would search "Events near me". I quickly learned that using structured data was the way to do this.

Here's an example for 'summer events in London':

A screenshot of the events section from google when searching for summer events in London.

Adding global structured data to a Next.js application

As I said earlier, It's actually quite easy to add the structured data to your next application. All you need is a script tag on your page. I like to add a general script tag to the <head> in my global layout.tsx. That looks something like the following:

app/layout.tsx
const structuredData = {
  "@context": "https://schema.org",
  "@type": "Organization",
  url: process.env.NEXT_PUBLIC_SITE_URL || "https://my-company.com",
  logo: "/logos/logo.webp",
  name: "My Company Name",
  legalName: "My Company Name Limited",
  telephone: "+447777777777",
  sameAs: ["https://www.linkedin.com/company/company-name/"],
}
export default function RootLayout() {
return (
	<html lang="en">
      <head>
        <script
          key="structured-data"
          type="application/ld+json"
          dangerouslySetInnerHTML={{
            __html: JSON.stringify(structuredData),
          }}
        />
      </head>
      <body>
          {children}
      </body>
    </html>
	)    
}

By placing it in the head tag this means that for every page indexed by google, there will be this organization information.

Adding specific structured data to a Next.js page

Now, not everything on our site is global and applies to each page, but this is an easy fix. If we have a product page we can simply add the following to our component:

app/product/[slug]/page.tsx
export default async function Page(){ 
	const product = await getProduct()
	const structuredData = {
		'@context': 'https://schema.org', 
		'@type': 'Product', 
		name: product.name, 
		image: product.image, 
		description: product.description,	
	}
	return (
		<div>
			<ProductCard product={product} />
	        <script
	          key="structured-data"
	          type="application/ld+json"
	          dangerouslySetInnerHTML={{
	            __html: JSON.stringify(structuredData),
	          }}
	        />
		</div>
	)
}
 

Writing effective structured data

Now there's lots you can add to your site, I'd strongly recommend taking a look at the google docs on this. Here are a few examples that I've used.

Events

event.json
    {
      "@context": "https://schema.org",
      "@type": "Event",
      name: "The most amazing event",
      startDate: "2024-07-21T23:00-05:00",
      endDate: "2025-07-21T23:00-05:00",
      eventAttendanceMode: "https://schema.org/OfflineEventAttendanceMode",
      eventStatus: "https://schema.org/EventScheduled",
      location: {
        "@type": "Place",
        name: "Event venue",
        address: {
          "@type": "PostalAddress",
          streetAddress: "Street Address",
          addressLocality: "Town",
          postalCode: "PO5T C0D",
          addressRegion: "County",
          addressCountry: "GB",
        },
      },
      image: ["/small_poster.webp", "large_poster.webp", "original_poster.webp"
      ],
      description: "This will be the best event of your life",
      organizer: {
        "@type": "Organization",
        name: "Organization",
        url: "https://probably-your-website.com",
      },
    },
 

Again your best bet is the Event Structured Data guide by google.

Blog Post

post.json
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      headline: "This is a cool blog post",
      image: ["small.webp", "large.webp"
      ],
      datePublished: "2024-02-15T00:00:00",
      dateModified: "2025-02-15T00:00:00",
      author: [
        {
	      "@type": "Person",
	      name: "Firstname LastName",
	      jobTitle: "Blog post writer",
	      worksFor: "Blog post company",
	      url: `${process.env.NEXT_PUBLIC_SITE_URL}/people/firstname-lastname`,
	      image: `${process.env.NEXT_PUBLIC_SITE_URL}/people/f_lastname.webp`,
        },
      ],
      description: "There are things in this post. Don't be vague like me",
    },

Typescript

So if you're anything like me, you are incapable of remembering anything and need typescript to tell you what comes next. Luckily, you can now do this for structured data using the schema-dts. Install it as a dev dependency:

pnpm i -D schema-dts

Then we can create our organization schema:

metadata/organization.ts
import { WithContext, Organization } from 'schema-dts'
 
export const organizationStructuredData: WithContext<Organization> = {
	"@type": "Organization",
	name: "Nice Organization Name"
}

Resources and Sources

  • Next.js docs - THE docs for adding this stuff to your page

Writing your schemas

Checking your schemas