Skip to content
Searchpedia SEO field notes Callum Bennett Callum

Site ops

Gatsby SEO

Gatsby does not fix SEO for you; it only gives you a fast foundation, and you still have to configure metadata, sitemaps and canonical URLs properly.

Beginner3 min readUpdated 2026-07-27Notes by Callum Bennett

Start here

  • Install gatsby-plugin-react-helmet and create a reusable SEO component that sets unique title, description and canonical URL per page.
  • Configure gatsby-plugin-sitemap to exclude draft, test or staging pages so search engines don't waste crawl budget.
  • Enforce a consistent trailing-slash policy in gatsby-config.js and on your server to avoid duplicate content issues.
  • Validate your sitemap and robots.txt in Google Search Console after every build to catch stray paths early.
  • Use the siteMetadata object in gatsby-config.js for site-wide defaults, but override them on each page to avoid thin content.

Plain-English take

Gatsby is a React-based static site generator that pre-renders HTML, which makes it a strong choice for SEO because search engines can crawl the content without executing JavaScript. The framework itself does not automatically optimise your pages; it provides the tools, and you must use them correctly. The core SEO work on a Gatsby site revolves around page-level metadata: unique title tags, meta descriptions, open graph tags, and canonical URLs. You typically manage these with a component powered by gatsby-plugin-react-helmet, which injects <head> elements at build time. For example, I have a SEO component that reads title, description, and canonical props and merges them with siteMetadata from gatsby-config.js. If I forget to pass a canonical prop, Gatsby will fall back to the current URL, which might include query parameters or trailing slashes that cause duplicates. The plugin ecosystem also handles structural SEO: gatsby-plugin-sitemap generates a sitemap.xml and gatsby-plugin-robots-txt creates a robots.txt. These are essential for telling search engines which pages to crawl and which to ignore. The trap is that the sitemap plugin includes every page by default, including draft blog posts, tag archives, or paginated pages you might not want indexed. I learned to filter those out using a serialize function. On the technical side, Gatsby sites are fast out of the box, which helps with [Core Web Vitals](/core-web-vitals/), but speed alone does not make a page rank. You still need proper [Technical SEO](/technical-seo/) signals like correct [Canonical Tags](/canonical-tag/) and a clean [Website Structure](/website-structure/).

When it actually matters

Gatsby SEO matters most when you are building a React-based site that needs to be indexed by search engines. Unlike a client-side rendered React app, Gatsby generates static HTML files at build time, so the content is immediately visible to crawlers. This is a significant advantage, but it introduces a new set of responsibilities. The moment you have more than a handful of pages, you need to manage metadata programmatically. I ran a Gatsby site with 500+ product pages. The sitemap plugin included all of them, but it also included draft variants and staging URLs that I had not meant to publish. Google crawled those drafts and marked them as soft 404s, wasting crawl budget. I had to write a custom serialize function that filtered out any path containing /draft/ or /staging/. That fixed the issue. Another common scenario is pagination. If you have a blog with paginated category pages, Gatsby generates /category/page/2/, /category/page/3/, etc. Without proper canonical tags pointing to the first page or a rel="next"/"prev" setup, you risk duplicate content signals. I use the gatsby-plugin-pagination or manual logic to add canonical URLs. Trailing-slash inconsistency is a frequent headache. By default, Gatsby lets you configure whether paths end with a slash, but if internal links use a mix of with and without, the site ends up with duplicate URL variants. I set trailingSlash: "always" in gatsby-config.js and added a server-side redirect to normalise incoming requests. This cleaned up the indexing confusion. For multilingual sites, [Hreflang Tags](/hreflang-tags/) are critical. Gatsby does not generate them automatically; you must pass them through your SEO component. The framework matters because it gives you a static base, but the SEO quality depends on your implementation discipline. If you skip these steps, your fast Gatsby site will still underperform in search.

What I got wrong

I originally assumed that because Gatsby is a static site generator, SEO was mostly handled. I thought the built-in HTML output would automatically include proper metadata and that plugins would work without configuration. That was naive. The first mistake: I used gatsby-plugin-react-helmet but did not pass a canonical URL prop. Gatsby fell back to the current URL, which included query parameters from a tracking script. As a result, the same page was indexed under multiple URLs with different query strings. I only noticed when Google Search Console showed a surge in duplicate pages. I fixed it by always setting an absolute canonical URL in the SEO component, prefixed with the site URL from siteMetadata. The second mistake: I relied on the default gatsby-plugin-sitemap without any filtering. It included every page, including draft blog posts I had set to draft: true in frontmatter. Those drafts were not meant to be public, but they were still generated and crawled. I had to add a serialize function that checked the frontmatter draft field and excluded those pages. The third mistake: I ignored trailing-slash configuration. My site had internal links that sometimes ended with a slash and sometimes did not, depending on how I wrote the path. Google indexed both versions, and I had to issue redirects to canonicalise them. I now set trailingSlash: "always" in gatsby-config.js and use a gatsby-plugin-force-trailing-slash to enforce it. The lesson is that Gatsby is a tool, not a solution. You still need to think about [JavaScript SEO](/javascript-seo/) patterns, [Duplicate Content](/duplicate-content/) prevention, and Performance Optimisation beyond the initial build. I also overlooked the importance of 301 Redirect for migrated pages; Gatsby's createRedirect action in gatsby-node.js works well for that. Admitting these mistakes helped me build a more reliable SEO process for every Gatsby project.

Next step

Quick answers

Does Gatsby automatically generate a sitemap?

No, you need to install gatsby-plugin-sitemap and configure it. The plugin will generate a sitemap.xml at build time, but you must filter out any pages you do not want indexed, such as drafts or paginated duplicates.

How do I add canonical URLs in Gatsby?

Use the gatsby-plugin-react-helmet to inject a <link rel="canonical" href="..." /> tag per page. Pass the absolute URL as a prop to your SEO component, typically combining the site URL from siteMetadata with the page path.

Can I use structured data on a Gatsby site?

Yes. You can add JSON-LD structured data by injecting a <script> tag via the same React Helmet component. For example, I use gatsby-plugin-schema or manual JSON-LD in the SEO component to output breadcrumbs, product, or article schema.

Sources

Primary documentation is linked directly. Anything commercial is marked nofollow.

Notes from Callum Bennett.