To ensure that websites are found by the intended users, search engines inspect websites for specific bits of metadata, like title, description, and keywords. Historically, Gatsby developers have been instructed to rely on third-party libraries like react-helmet to do this. Gatsby has built-in solutions for most things like Images or Scripts that our users have come to love.
To continue the trend of shipping fundamental website building blocks as part of Gatsby, we’re excited to Introduce Gatsby Head API — available in Gatsby@4.19 or later. It helps you fluently update the document head of your page with zero addon needed. This feature is built in such a way that it’s 100% compatible with React’s suspense/streaming capabilities.
Aside from updating your document head in the browser, the Head API takes it even further and automatically adds the tags into the generated HTML so you no longer need an extra Gatsby plugin in your gatsby-config.js
for this to work.
To use this feature, you must export a Head
function that returns Jsx in your page or page template.
Why not components
You’re completely correct if you’re wondering, “Why isn’t this just a <Head>
component?”
One reason the named exports really stood out is due to React concurrent features like streaming and selective hydration, and how mixing these React features with the component pattern can be problematic and tricky. Let’s explore one of the problems that the streaming model poses.
Unpredictable rendering order
When we server-render site components with React’s .renderToString()
,the result is a fully rendered HTML string, tags are rendered in a predictable order and everyone is happy.
Since React 18, React has added streaming capabilities. With its renderToPipeableStream
API, React streams HTML as it becomes available, whereas previously React would wait until the entire document was ready before sending any content to the client browser. Components can then:
- Stream the fallback HTML
- Suspend and wait for async operation to complete
- React streams the rest of the components as they become available
While that sounds great, the issue is that when you have multiple async operations, you can’t determine which one completes first and hence can’t determine the order of the tags.
Example
Let’s say we have multiple components (<ComponentA/>
and <ComponentB/>
). These component are wrapped in individual suspense boundaries and each of them renders tags to the document head using <Helmet>
With the above setup, HTML for components that are ready will immediately get streamed—in this case, that’s the HTML for <Spinner>
since the spinner will be readily available.
Since we have some asynchronous operations in <ComponentA>
and <ComponentB/>
it would be difficult or impossible to predict which component will be ready next. If one of the async operations takes a short time, HTML for that is streamed first. What ends up happening is that the tags get added to <head>
but the order would be neither predictable nor consistent.
This becomes problematic when you need to load one resource (e.g script) before the other. Also, this may cause link preloads to malfunction since there’s no guarantee they’d get discovered on time.
Our approach
Generally speaking, since the streaming model renders in bits and the components-approach renders stuff outside of the component tree, the components-approach doesn’t easily fit into this model.
Our approach eliminates this pitfall by letting you define head additions for each page separately—outside the component tree. This ensures deterministic loading of tags, thereby making the tags and loading sequence both predictable and consistent.
Though we considered multiple approaches to solve this problem, we chose named exports for the following reasons:
- Gatsby has precedent with named export function APIs
- We can escape all the gotchas with React’s concurrent rending and provide a solution that is 100% compatible with React of today
- Favor vanilla JavaScript where reasonable to do so
- Does not require expertise from the user when building sites with React’s Supsense/Streaming
Perceived limitation of current approach
With components, you could throw Helmet or some <Seo>
component into a <Layout>
component and use that to wrap your pages.
With the new Head API, you directly add a Head
export to every page that needs to update the document head.
You don’t have to repeat tags all over the place since you can put them in a component and use that across Head exports. Our SEO component documentation goes into detail on how you can create and use a SEO component in your site.
Wrapping up
The Gatsby Head API is easy-to-use, more performant and future-proof. Though migration is quite straightforward, we recommend migrating your sites slowly. If you’re looking for examples, this example site is a good place to start. For larger sites, our gatsby-starter-shopify will be more ideal as it has more usage examples.
One thing you’ll notice while migrating your site to the Gatsby Head API is that you can’t add metadata to your pages by wrapping them with a With the Head API, you get the benefit of co-locating your head additions within the page template as opposed to putting them in a <Layout />
component
We realize that our users appreciate it when key website building blocks are included by default in Gatsby. This approach allows developers to focus on creating highly performance sites, and not worry about searching for the next dependency to install.
As always, we’d love your feedback on the new API! Share your thoughts in the public discussion on the RFC: Gatsby Head API.