Migration from React Helmet to the new Head API

We had so much fun on yesterday's unauthorized and rum-fueled treasure hunt in the sharky waters around the Gatsby islands πŸŽ‰

Stream Screendump

The What?

We migrated from React Helmet to the new React Head API.

The Why?

It's always nice to get rid of dependencies, and I have seen some very intermitted issues with missing meta tags on a few pages, as reported by ahrefs. Hopefully, that will be a thing of the past after the migration.

The How

We made sure to enable migrating one page at a time instead of migrating it all at once. Experience has taught me the perils of the latter approach.

So we cloned the existing SEO component, named it PageHead, and replaced the Helmet wrapper with a fragment <>...</>.

We then returned the new PageHead component from the named export Head in the page template.

The new Head API asks you to export a named component called Head. Similar to how Gatsby picks up the default export as the content to inject into the body element, the named export query as the page query, it now also picks up the named export Head as content to inject into the head element.

The Code

// File: src/pages/{Email.slug}.js
import React from "react";
import { graphql, Link } from "gatsby";
import PageHead from "../components/page-head";
import EmailTemplate from "../components/email-template";

export function Head({ data, ...props }) {
  const { title, description } = data.email || {};
  return (
        title: title,
        description: description,

export default function EmailPage({ data, ...props }) {
  return <EmailTemplate {...data.email} {...props} />;

export const query = graphql`
  query EmailById($id: String!) {
    email(id: { eq: $id }) {
      // ... the query

Check out the Pull Request on Github to view the full refactor we did on stream.


All the best,
Queen Raae

Interested in more daily treasures like this one?
Sent directly to your inbox?