Gatsby SEO: static HTML, the Head API, and what to watch
You picked Gatsby for speed and a React workflow. Search sees your static HTML, then the page hydrates with JavaScript. This guide shows how to ship clean metadata, a working sitemap and fast images, what to watch in Core Web Vitals, and where teams migrate when maintenance bites.
By Théophile Louvart, founder of Porteur · Updated 14 September 2026 · Markdown
What good Gatsby SEO looks like today
You render static HTML that crawlers can read, then hydrate on the client. That is fine for ranking, if the static HTML carries your real content and metadata.
- Set titles, descriptions, canonicals and social tags with the Head API, not in client-only effects.
- Ship a sitemap with gatsby-plugin-sitemap and submit it in Search Console.
- Optimise images with gatsby-plugin-image so LCP sits at or under 2.5 s and CLS stays at or under 0.1.
- Keep hydration light so INP stays under 200 ms on key pages like / and /pricing.
- Plan for maintenance: Gatsby’s pace has slowed since 2023, so check plugin health and consider migration paths.
Titles, descriptions and canonicals with the Head API
Use the Head API to declare metadata at build time. Older sites often used react-helmet. On a new or updated site, prefer Head so your defaults live in layouts and templates.
// src/pages/pricing.js
import * as React from "react"
export default function PricingPage() {
return (
<main>
<h1>Pricing</h1>
{/* page content */}
</main>
)
}
export function Head() {
const title = "Pricing for YourProduct"
const description = "Plans for startups and teams. Cancel any time."
const canonical = "https://yourproduct.com/pricing"
const ogImage = "https://yourproduct.com/og/pricing.png"
return (
<>
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImage} />
<meta name="twitter:card" content="summary_large_image" />
</>
)
}
Set a default Head in your root layout and override per page. Keep titles under about 60 characters so results do not truncate. Write descriptions between 120 and 155 characters to fit most snippets.
Put shared tags in a Layout Head
Add site name, default og:image and a fallback description. Pull per-page values with props or page queries.
Avoid client-only metadata
Do not set titles in useEffect. Crawlers read your HTML. Put everything important in Head.
The sitemap with gatsby-plugin-sitemap
Generate a sitemap so Search can discover pages fast. Gatsby does not ship one by default. Use gatsby-plugin-sitemap and check its output after every deploy.
// gatsby-config.js
module.exports = {
siteMetadata: {
siteUrl: "https://yourproduct.com",
},
plugins: [
{
resolve: "gatsby-plugin-sitemap",
options: {
excludes: ["/drafts/*", "/private/*"],
createLinkInHead: true,
},
},
],
}
Set siteUrl
Put the canonical origin in siteMetadata. Use https and your chosen www or non-www form.
Exclude non-indexable paths
If you ship drafts under /drafts/, exclude them. Also add noindex in Head on those pages.
Verify in Search Console
Submit /sitemap-index.xml in the Sitemaps report. Fix path errors. Resubmit after major URL changes.
A correct setup will output a sitemap index and child sitemaps for pages. Your /pricing and /guides/getting-started should appear with the right lastmod dates after a content update.
Images with gatsby-plugin-image: LCP, CLS and size hints
Images decide speed and layout stability. Use gatsby-plugin-image to transform and serve responsive images. It helps Largest Contentful Paint and avoids layout shift with fixed dimensions.
// Hero image in a page component
import { StaticImage } from "gatsby-plugin-image"
export default function Home() {
return (
<header>
<h1>Build docs people read</h1>
<StaticImage
src="../images/hero.png"
alt="Dashboard screenshot"
width={1200}
height={630}
placeholder="blurred"
formats={["avif", "webp", "png"]}
priority
/>
</header>
)
}
- Set width and height to give the browser exact size. This keeps CLS at or under 0.1.
- Use priority on the LCP image above the fold, for example the hero on /.
- Serve modern formats like AVIF and WebP. Let the plugin generate multiple sizes.
- Use GatsbyImage with GraphQL for CMS images inside templates.
- Avoid giant social images in the markup outside of the Head. Put og:image only in metadata.
Check PageSpeed Insights for field data. Good LCP is up to 2.5 seconds. If LCP is an image, trim bytes and avoid blocking scripts above it. Lazy load below-the-fold images only, not the hero.
Hydration weight and Interaction to Next Paint
Gatsby ships static HTML. Then it hydrates with JavaScript. Heavy hydration penalises Interaction to Next Paint. Keep client-side work lean on landing pages you want to rank and convert.
- Remove interactive widgets on content pages that do not need them: carousels, heavy chat launchers, complex animations.
- Avoid rendering core content only on the client. Static HTML should contain headings, copy and links.
- Audit third-party scripts. Defer marketing tags and cut unused ones. Check their impact on INP in PageSpeed Insights.
- Prefer simple components for navigation and accordions. Keep event handlers small and fast.
- Test on a mid-range phone. Lighthouse simulates one run, results vary. Rerun a few times and focus on Core Web Vitals in the field.
Aim for good thresholds as of 2026: INP up to 200 ms, LCP up to 2.5 s, CLS up to 0.1. Field assessment uses the 75th percentile over 28 days. You will see those in the Core Web Vitals report in Search Console when there is enough traffic.
Maintenance has slowed: what to watch and when to migrate
Gatsby maintenance has slowed since 2023. That does not break your SEO by itself. It affects how fast bugs and integrations move. Treat plugin choice and updates with care as of 2026.
- Check the health of key plugins: sitemap and image. Read their repositories and changelogs before you upgrade.
- Keep Node and dependencies in a version set your host supports. Pin versions for stability.
- Test builds on a staging URL with noindex. Crawl the stage for broken links and missing metadata before a release.
- If team skills have shifted to another framework, plan a migration with URL parity and redirects.
Migration paths teams take from Gatsby
Most teams move for ecosystem and hiring reasons, not for pure SEO. The common paths keep React or go more static. Keep your URLs and metadata identical. Ship 301 redirects when they must change.
| Move to | Metadata | Sitemap and robots | Images | Watch for |
|---|---|---|---|---|
| Next.js | Use the Metadata API for titles, descriptions and canonicals. Map your Gatsby Head to layout.tsx and page files. | Use sitemap.ts and robots.ts. Keep the same site URL and paths. | Use next/image for responsive images. | Avoid heavy client components on content pages. Static rendering by default helps. |
| Astro | Set titles and metadata in layouts. No built-in SEO layer, you write the head as you do in Gatsby. | Use @astrojs/sitemap. Replace or extend the automatic sitemap as needed. | Built-in image optimisation with zero JavaScript by default. | Pages ship zero JS unless added, which improves INP. Keep URL parity. |
| Docusaurus | Front matter for title and description on docs. Good for product docs and guides. | Use the sitemap plugin. Versioned docs need careful canonicals or noindex on old versions. | Use its image pipeline inside the theme. | Avoid duplicate pages across doc versions. Canonicalise the current. |
Freeze the Gatsby site
Generate a list of all indexable URLs, titles, descriptions and canonicals. Export your sitemap and crawl it.
Build URL parity first
Match slugs and trailing slashes. Keep /guides/getting-started as /guides/getting-started.
Carry over metadata
Port Head tags one for one. Verify social tags and structured data.
Ship redirects
For changed paths, add 301s. Test in bulk. Keep them long term.
Verify in Search Console
Submit the new sitemap. Watch the performance and Core Web Vitals reports for shifts over the next 28 days.
Checks before and after you ship
- Page-level: title under about 60 characters, description under 155, one canonical, primary h1, real content in static HTML.
- Site-level: sitemap index resolves, includes only indexable pages, no 404s inside it.
- Links: no orphan pages you want to rank. Internal links use the real final URL, not tracking parameters.
- Speed: LCP up to 2.5 s, CLS up to 0.1, INP up to 200 ms on /, /pricing, and top guides.
- Search Console: sitemap submitted, no spikes in warnings, URL Inspection returns the expected canonical.
A fixed page looks like this: /pricing has a unique title and description in Head, a canonical to https://yourproduct.com/pricing, the hero image as LCP with priority, and the page loads with stable layout and fast input response on a mid-range phone on throttled 4G in Lighthouse.
Troubleshooting: pages shown but never clicked
If impressions rise but clicks do not, your snippet is not pulling its weight or the intent is off. Start with the queries in the Search Console performance report and fix the page they map to.
- Rewrite the title to match the query, for example change “Pricing” to “YourProduct pricing and plans”.
- Tighten the description to match the benefit in one line, for example “Ship guides, search logs and dashboards. Plans for startups and teams.”
- Add an internal link from a higher traffic page to push a relevant page up a level.
- Avoid cannibalisation: do not run two guides on the same query. Merge and redirect the weaker one.
Questions
Yes, if your pages render static HTML with real content and metadata, Gatsby can rank. The Head API, gatsby-plugin-image and a sitemap cover the basics. The pace of maintenance has slowed since 2023, so watch plugin health and plan for the future.
Use the Head API on new or updated sites. It lets you declare metadata at build time in page and template files. Keep react-helmet only if you inherit an older codebase and cannot refactor right now.
Yes if you want an XML sitemap. Gatsby does not ship one by default. Install gatsby-plugin-sitemap, set siteUrl and submit the sitemap index in Search Console. Exclude non-indexable paths.
Yes. With optimised images and light hydration, you can keep LCP up to 2.5 s, CLS up to 0.1 and INP up to 200 ms. Check field data in PageSpeed Insights and the Core Web Vitals report in Search Console.
Client-only rendering of content, missing canonicals, and forgetting the sitemap. Keep metadata in Head, render content statically, and verify the sitemap. Trim third-party scripts that harm INP.
Next.js, Astro and Docusaurus are common moves. SEO breaks when URL paths change without 301 redirects, metadata is lost, or the sitemap is wrong. Build URL parity, port Head tags, and ship redirects.
Sources
Check my site, free
Paste your homepage URL to get a free 30-second read on your pages, the searches around them and the rivals on them, with three findings shown in full.
- Free check, no card
- Read-only, your own accounts
- Readable by your agent
Read next
- GuideOn-page SEO checklist: the twelve things on the page
- GuideTitle tag length: what fits, what Google rewrites, and how to write one
- GuideMeta description length, with examples that earn the click
- GuideCore Web Vitals for a product site: the three numbers
- GuideImage optimisation for page speed: the hero image and everything below it
- GuideThe Sitemaps report: what Success, Has errors and Couldn’t fetch mean
- GuideAstro SEO: fast by default, and the layout work that remains
- GuideDocusaurus SEO: docs that rank and versions that do not fight