Dynamic SEO in Next.js

Author : JaNakh Pon , August 30, 2021

Tags

How to add SEO meta tags dynamically to Next.js app

We are going to the repo from the previous article and add SEO dynamically in a few steps.

Summary

In this article, we are going to add SEO meta tags dynamically to Next.js demo app instead of using the same meta tags for the whole app.

And we will need the default configuration values for default fallback if the route doesn't have custom properties to use in meta tags.

In order to do that, we will need a file named: config.ts to store default configurations, SEO Component to handle SEO meta tags and Layout wrapper for pages.

Finally, we will use the Layout wrapper to pass custom SEO properties and if we don't pass them to SEO Component, it will use the default configurations.


Requirements ( config.ts, SeoComponent, LayoutWrapper)

Let's start by creating a file to store configurations:

config.ts
const metadata = {
  siteName: 'Hello Site',
  description: 'Hello ballo website',
  siteUrl: 'http://localhost:3000/',
  siteImage: 'mstile-150x150.png',
  siteContent: 'Hello, Site, Test, Demo',
  author: {
    name: 'Ja Nakh Pon',
    twitter: '@ja_nakh',
  },
}
export { metadata }

And SeoComponent:

seo.tsx
import Head from 'next/head'
import { metadata as siteMeta } from 'config'

export type SEOProps = {
    title?: string
    description?: string
    image?: string
    url?: string
}

const SEO = ({ title, description, image, url }: SEOProps) => {
    const pageTitle = title
        ? `${title} | ${siteMeta.siteName}`
        : siteMeta.siteName
    const pageDescription = description ? description : siteMeta.description
    const pageImage = image ? image : siteMeta.siteImage
    const pageUrl = url ? url : siteMeta.siteUrl

    return (
        <Head>
            <title>{pageTitle}</title>
            <meta name="description" content={pageDescription} />
            {/* OpenGraph | Facebook */}
            <meta property="og:title" content={pageTitle} />
            <meta property="og:description" content={pageDescription} />
            <meta property="og:type" content={'website'} />
            <meta property="og:url" content={pageUrl} />
            <meta property="og:locale" content="en_IE" />
            <meta property="og:site_name" content={pageTitle} />
            <meta property="og:image" content={pageImage} />
            {/* <meta property="og:image:width" content="1200"/>
            <meta property="og:image:height" content="630"/> */}
            {/* Twitter */}
            <meta property="twitter:title" content={pageTitle} />
            <meta property="twitter:description" content={pageDescription} />
            <meta property="twitter:card" content="summary_large_image" />
            <meta property="twitter:site" content={siteMeta.author.twitter} />
            <meta property="twitter:creator" content={siteMeta.author.twitter} />
            <meta name="twitter:image" content={pageImage} />
            {/* <meta property="og:image:width" content="1200"/>
            <meta property="og:image:height" content="600"/> */}
            {/* Root */}
            <link rel="canonical" href={pageUrl} />
        </Head>
    )
}
export default SEO

Finally, LayoutWrapper:

page.tsx
import { ReactNode } from 'react'
import SEO, { SEOProps } from '@components/seo'

type PageProps = {
  meta?: SEOProps
  children?: ReactNode
}

const Page = ({ meta, children }: PageProps) => (
  <>
    <SEO {...meta} />
    <>
    {children}
    </>
  </>
)
export default Page

Since we already have the meta tags for OpenGraph and Twitter in SEO Component, we can remove them from _document.tsx.

Now we need to use LayoutWrapper and provide custom properties to it in index.tsx and about.tsx:

index.tsx
import type { NextPage } from 'next'
import Page from '@layouts/page'
import styles from '@styles/Home.module.css'

const Home: NextPage = () => {
  return (
    <Page
      meta={{
        title: "Dynamic",
        description: `Website's home page`,
      }}>
      <div className={styles.container}>
        <main className={styles.main}>
          {/* blah blah blah blur blur blur */}
        </main>
      </div>
    </Page>
  )
}
export default Home

and

about.tsx
import Page from "@layouts/page";

const About = () => (
  <Page
    meta={{
      title: "About",
      description: `Website's about page`,
      url: 'http://localhost:3000/about'
    }}>
    <h1>About</h1>
  </Page>
);
export default About;

Since everything is ready now, let's build it and serve it in local. So, we could check the results using Lighthouse:

 > npm run build && npm run start
 > \\ Open Dev Tools > Lighthouse > Generate reports

Congrats!!! now you can add custom meta tags for SEO in each route of your Next.js App 😉.


Source Code.