Adding a Sitemap & SEO to your NextJS Statically Generated Site

Adding a Sitemap & SEO to your NextJS Statically Generated Site

Today I'm going to do some basic SEO work for this site. I thought I would take the opportunity to log my how-to here. More content, right? 😉

Here are the additions I'll be making:

  1. A statically generated sitemap & robots.txt
  2. Basic SEO & OpenGraph data to all pages & articles

To implement this stuff, I'll be using 2 excellent packages:

  1. next-sitemap
  2. next-seo

Let's get started.

Adding a sitemap in your NextJS site

First thing you'll want to do is add the package to your site

$ yarn add next-sitemap

Then, in your package.json file, you're going to want to set up a postbuild script. Mine looks like this:

package.json
{
  "name": "tybarho.com",
  ...
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postbuild": "next-sitemap"
  },
}

Now, I want to be sure that all of my markdown files are indexed to my generated sitemaps. Sitemaps are generated after NextJS statically builds my site. For some context, here is my rough folder structure:

/src
  /components
  /content
    /articles
      slug-of-article.mdx
    /lessons
      slug-of-lesson.mdx
  /pages
    index.js
    /articles
      [slug].js
      index.js
    /lessons
      [slug].js
      index.js

So I need to tell next-sitemap about the files in /content/articles and /content/lessons. Luckily, I can do this with a custom config.

To add a custom config, in your project root, add a file called next-sitemap.config.js. For my site, this will be the contents of that file.

next-sitemap.config.js
const fs = require('fs')
const path = require('path')

module.exports = {
  siteUrl: 'https://www.tybarho.com',
  sitemapSize: 7000,
  exclude: [],
  generateRobotsTxt: true,
  additionalPaths: async (config) => {
    let result = []

    const articles = fs.readdirSync(path.resolve('./src/content/articles'))
    const lessons = fs.readdirSync(path.resolve('./src/content/lessons'))

    for (const article of articles) {
      result.push(
        await config.transform(
          config,
          `/articles/${article.replace('.mdx', '')}`
        )
      )
    }

    for (const lesson of lessons) {
      result.push(
        await config.transform(config, `/lessons/${lesson.replace('.mdx', '')}`)
      )
    }

    return result
  },
  robotsTxtOptions: {
    policies: [
      {
        userAgent: '*',
        allow: '/',
      },
    ],
  },
}

To test it out, run:

$ yarn postbuild

This should generate files at /public/sitemap.xml and /public/sitemap-0.xml that you can review to make sure they look right, and all your pages are included.

And that's that!

NOTE: If you're not seeing every page in your sitemap, try re-running the full yarn build command to generate a new /.dist folder.

Adding decent SEO to your NextJS site

Now, to add some SEO & OpenGraph data to my pages, I'm going to use the next-seo package.

Start by installing it:

$ yarn add next-seo

Now, the first thing we want to do is add some base SEO to every page on our site. We can do this by editing our pages/_app.jsx. If you don't have one, create one.

src/pages/_app.jsx
import { useEffect, useRef } from 'react'
import { DefaultSeo } from 'next-seo'

import { Footer } from '@/components/Footer'
import { Header } from '@/components/Header'

import '@/styles/tailwind.css'
import 'focus-visible'

function usePrevious(value) {
  let ref = useRef()

  useEffect(() => {
    ref.current = value
  }, [value])

  return ref.current
}

const baseUrl = 'https://www.tybarho.com'

export default function App({ Component, pageProps, router }) {
  let previousPathname = usePrevious(router.pathname)

  return (
    <>
      <DefaultSeo
        openGraph={{
          type: 'website',
          locale: 'en_US',
          url: `${baseUrl}`,
          site_name: 'TyBarho.com',
        }}
      />
      <div className="fixed inset-0 flex justify-center sm:px-8">
        <div className="flex w-full max-w-7xl lg:px-8">
          <div className="w-full bg-white ring-1 ring-zinc-100 dark:bg-zinc-900 dark:ring-zinc-300/20" />
        </div>
      </div>
      <div className="relative">
        <Header />
        <main>
          <Component previousPathname={previousPathname} {...pageProps} />
        </main>
        <Footer />
      </div>
    </>
  )
}

The main thing here is the <DefaultSeo ... /> component we're adding. There are a ton of options you can configure, but we're just starting with some base ones.

Now, let's add some custom SEO data to our home page.

src/pages/index.js
// Other imports
import { NextSEO } from 'next-seo';

// ...

export default function Home({ articles }) {
  const title = 'Ty Barho'
  const description = "I'm Ty, a software designer and entrepreneur based in Georgetown, Texas. I like to make things that help people."
  const canonical = 'https://www.tybarho.com';
  
  return (
    <>
      <NextSEO
        title={title}
        description={description}
        canonical={canonical}
        openGraph={{
          url: canonical,
          title,
          description,
        }}
      />
      <Container className="mt-9">
      {/* rest of code */}
    </>
  );
}

Now, open your developer console to verify the new SEO data is on your page.

NextSEO Check Image

Looks like it worked! ✨🦄

Now you can easily add SEO data to any page on your NextJS site.

Checking your OG Data

Once you've deployed your site, or using a tool like ngrok, you probably want to see what your OG data is going to look like on different platforms.

My favorite site for this is OpenGraph.XYZ.

Just put your URL in, and you'll get a nice preview of what your OG data will look like on different platforms.

OpenGraph.XYZ

And that's that! Happy SEO-ing! 🚀

If you enjoyed this article, please consider following me on Twitter

Subscribe to the Newsletter

Subscribe for exclusive tips, strategies, and resources to launch, grow, & build your SaaS team.

Share this article on: