How to Use the Gatsby Slice API for Partial Hydration and Large Site Performance
The Gatsby Slice API lets you build shared UI components once and stitch them into thousands of pages, while Partial Hydration (Beta) ensures only interactive slices ship JavaScript to the browser, reducing incremental build times by up to 90% and dramatically shrinking bundle sizes.
Gatsby 5 introduced the Slice API alongside Partial Hydration (Beta) to eliminate performance bottlenecks on large sites. According to the gatsbyjs/gatsby source code, this architecture extracts highly-shared components—such as headers, footers, and cards—into discrete build units that render once and stitch into every page. By implementing the Gatsby Slice API for partial hydration, you generate static HTML for non-interactive content while shipping JavaScript only for components that require client-side interactivity, resulting in significantly faster builds and smaller browser payloads.
How the Slice API Works Internally
The Slice API operates through a deterministic build pipeline defined in the Gatsby core. When you call createSlice in gatsby-node.js, the system validates the component, generates a unique identifier, and manages rendering through specialized workers and webpack plugins.
Slice Registration and Validation
In packages/gatsby/src/redux/actions/restricted.ts, the createSlice action validates the id, component path, and optional context before registering the slice in the internal Redux store as type IGatsbySlice. The packages/gatsby/src/utils/slices.ts utility provides getSliceId, which generates a deterministic slice ID from the component chunk name and a content digest of the slice context. This ensures that identical slices produce identical IDs across builds, enabling aggressive caching.
Build-Time Rendering and Stitch Directives
During the HTML build phase, Gatsby renders each slice exactly once. The packages/gatsby/src/utils/worker/child/render-html.ts worker executes renderPartialHydrationProd to generate static HTML for every slice, saving these as discrete static files. When constructing individual pages, Gatsby replaces the <Slice alias="…"> placeholder with a stitch directive that points to the pre-rendered slice HTML, avoiding redundant rendering of shared components across thousands of pages.
Partial Hydration Integration
When you enable Partial Hydration via flags.PARTIAL_HYDRATION, the packages/gatsby/src/utils/webpack/plugins/partial-hydration.ts plugin (implemented as PartialHydrationPlugin) analyzes slice components. It emits partial-hydration chunks only for slices containing client-side code (marked with "use client"), while keeping purely static slices as raw HTML. At runtime, packages/gatsby/src/components/slice.tsx lazy-loads JavaScript exclusively for interactive slices, leaving static markup untouched in the DOM.
Implementing Slices for Partial Hydration
To leverage the performance benefits, you must define slices at the data layer, place them in your layouts, and configure the Partial Hydration flag.
Defining Slices in gatsby-node.js
Use actions.createSlice to register shared components. The id identifies the slice globally, while context passes data to the component as sliceContext.
exports.createPages = async ({ actions }) => {
actions.createSlice({
id: `site-header`,
component: require.resolve(`./src/components/header.js`),
context: { siteTitle: `My Awesome Site` },
})
}
This registration occurs in packages/gatsby/src/redux/actions/restricted.ts, where the action creator validates that the component path exists and the ID is unique.
Rendering Slices with the Slice Component
Import the Slice component from gatsby and use the alias prop to reference your slice. The alias defaults to the slice ID if omitted.
import { Slice } from "gatsby"
import { Footer } from "./footer"
export const Layout = ({ children }) => (
<div className="layout">
<Slice alias="site-header" />
{children}
<Footer />
</div>
)
At build time, Gatsby replaces this placeholder with a stitch directive pointing to the pre-rendered HTML generated by the worker in packages/gatsby/src/utils/worker/child/render-html.ts.
Mapping Aliases for Dynamic Content
You can map generic aliases to specific slice IDs on a per-page basis. This is useful when the same layout requires different slice instances for different pages.
exports.createPages = ({ actions }) => {
const animals = ['dog', 'cat', 'giraffe']
animals.forEach(animal => {
actions.createSlice({
id: `animal-image-${animal}`,
component: require.resolve(`./src/components/animal-image.js`),
context: { animal },
})
actions.createPage({
path: `/animals/${animal}`,
component: require.resolve(`./src/templates/animal-page.js`),
slices: {
'animal-image': `animal-image-${animal}`,
},
})
})
}
The slices object in createPage maps the alias used in your JSX to the specific slice ID registered for that page.
Adding GraphQL Queries to Slices
Slices support static queries that receive context variables via the sliceContext prop. Export a GraphQL query using the variable names passed in createSlice.
import * as React from "react"
import { graphql } from "gatsby"
export const query = graphql`
query ($siteTitle: String) {
site {
siteMetadata {
title
description
}
}
}
`
export default function Header({ data, sliceContext }) {
return (
<header>
<h1>{sliceContext.siteTitle}</h1>
<p>{data.site.siteMetadata.description}</p>
</header>
)
}
The query executes at build time, and the $siteTitle variable is populated from the context object passed to createSlice.
Enabling Partial Hydration (Beta)
To activate Partial Hydration and prevent static slices from shipping JavaScript, add the flag to gatsby-config.js.
module.exports = {
flags: {
PARTIAL_HYDRATION: true,
},
}
With this enabled, the PartialHydrationPlugin in packages/gatsby/src/utils/webpack/plugins/partial-hydration.ts analyzes each slice's imports. Only slices containing React Server Components with client directives receive JavaScript chunks; all others remain as static HTML stitched into the page.
Performance Impact on Large Sites
According to the Gatsby 5 release notes and implementation in packages/gatsby/src/utils/slices.ts, the Slice API delivers substantial optimizations:
- Faster Incremental Builds: Changing a highly shared component (like a navigation bar) triggers only the slice rebuild, not a full rebuild of every referencing page. This achieves up to 90% reduction in incremental build times for content changes in shared components.
- Reduced JavaScript Payloads: Partial Hydration ensures browsers download JavaScript only for interactive slices. Static headers, footers, and content cards ship as HTML with zero client-side overhead, improving First Contentful Paint and Interaction Ready metrics.
- Deterministic Caching: The
getSliceIdutility creates content-based hashes, ensuring unchanged slices persist across builds while modified slices invalidate precisely.
Summary
- The Slice API extracts shared UI components into single-render units that stitch into pages via HTML directives, defined in
packages/gatsby/src/redux/actions/restricted.tsand rendered inpackages/gatsby/src/utils/worker/child/render-html.ts. - Partial Hydration, controlled by
flags.PARTIAL_HYDRATIONand implemented inpackages/gatsby/src/utils/webpack/plugins/partial-hydration.ts, restricts JavaScript bundling to only those slices containing interactive code. - Use
actions.createSlicewithid,component, and optionalcontextto register slices, then render them with<Slice alias="id">in your layouts. - Map dynamic aliases per page using the
slicesoption inactions.createPagefor flexible, data-driven layouts. - Combine both features to achieve up to 90% faster builds on large sites while minimizing client-side JavaScript execution.
Frequently Asked Questions
What is the difference between a Slice and a regular React component?
A Slice is a React component extracted at build time by Gatsby's rendering pipeline. Unlike standard components that render as part of each page's bundle, slices generate deterministic IDs via getSliceId in packages/gatsby/src/utils/slices.ts and render once into static HTML. This allows Gatsby to stitch the same HTML into multiple pages without re-rendering the component for every page build.
How does Partial Hydration determine which slices receive JavaScript?
The PartialHydrationPlugin in packages/gatsby/src/utils/webpack/plugins/partial-hydration.ts scans slice components for the "use client" directive or client-side imports. Slices containing such markers compile into separate JavaScript chunks loaded by packages/gatsby/src/components/slice.tsx at runtime. Purely static slices without client code remain as server-rendered HTML with no browser JavaScript overhead.
Can I pass dynamic data to a Slice without triggering full hydration?
Yes. Pass data via the context option in createSlice, which becomes available as sliceContext. For static data, export a GraphQL query from the slice component using variables matching your context keys. This data resolves at build time, keeping the slice static unless you explicitly add interactive client components.
What happens to my site when I update a component used in multiple slices?
Gatsby rebuilds only the affected slice based on its content digest and ID generation logic in packages/gatsby/src/utils/slices.ts. Because pages reference slices through stitch directives rather than embedding the component directly, updating a shared navigation slice does not rebuild every page that displays it—only the slice file regenerates, and pages receive the new HTML via updated stitch references.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →