Speed up Gatsby image loading with build-time optimization
Use gatsby-plugin-image to generate WebP, AVIF, and responsive srcSets at build time instead of shipping heavy unoptimized images.
16 Sept 2025, 18:13 UTC

Heavy images delay your Gatsby pages before hydration
A static Gatsby site can still ship unoptimized images. If you drop a multi-megabyte JPEG into a page and reference it with a standard tag, every visitor downloads that full file regardless of screen size. On mobile networks, that delays the largest contentful paint and can shift layout while the browser reserves space for an image whose dimensions it does not yet know.
The useful takeaway: gatsby-plugin-image processes images during gatsby build, generating WebP and AVIF variants plus a responsive srcSet. The browser then downloads only the size and format it needs, and the markup reserves the correct space up front.
Version assumptions and setup
This guide assumes Gatsby v3 or v4. The plugin’s modern GatsbyImage API is not available on Gatsby v2 without a major upgrade. Install the plugin and its image-processing peers from your project root. You need normal write permissions for node_modules and package.json.
npm install gatsby-plugin-image gatsby-plugin-sharp gatsby-source-filesystem
Add the plugins to gatsby-config.js. The path placeholder should point to the folder that contains your source images.
module.exports = {
plugins: [
`gatsby-plugin-image`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
],
}
This changes project state. To undo, remove the plugin block from gatsby-config.js, revert package.json and package-lock.json, then run npm install again.
Query image data and render it
Gatsby’s GraphQL layer reads image metadata at build time. Query childImageSharp.gatsbyImageData to get the optimized image object. Replace hero.jpg with an actual file in your images folder.
query {
file(relativePath: { eq: "hero.jpg" }) {
childImageSharp {
gatsbyImageData(
width: 800
layout: CONSTRAINED
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
Pass that data to GatsbyImage. The component renders an img tag with a generated srcSet and optional blurred placeholder.
import { GatsbyImage, getImage } from "gatsby-plugin-image"
export default function Hero({ data }) {
const image = getImage(data.file)
return
}
getImage is a helper that normalizes the GraphQL result so the component can consume it. layout: CONSTRAINED means the image scales down to fit its container but never exceeds the requested width. formats: [AUTO, WEBP, AVIF] tells Gatsby to generate modern formats and let content negotiation pick the best one.
Verify the production build
Run the build from your project root:
npx gatsby build
Open the generated HTML in public/ and search for srcSet. You should see multiple width descriptors such as 400w, 800w, and 1200w alongside image/webp or image/avif type hints. If the markup contains only one unsized src attribute, the plugin did not process the image.
Next, start the production server and open DevTools:
npx gatsby serve
In the Network tab, reload the page and filter by image. When the browser supports WebP or AVIF, the response should use one of those MIME types rather than the original JPEG or PNG. Off-screen images should not appear in the initial waterfall if lazy loading is active.
For a broader check, run Lighthouse against the served URL and compare the "Serve images in next-gen formats" and "Properly size images" audits before and after adding the plugin.
Trade-offs to consider
- Build time. Every image is processed at build time. A site with hundreds of high-resolution photos can noticeably slow
gatsby buildand incremental builds. - Static content only. The build-time GraphQL approach works for images known when the site is built. User-uploaded images require a different strategy, such as an external image CDN or runtime image processing.
- Not a CDN replacement. The plugin optimizes file size and format, but it does not distribute images globally. Pair it with a CDN if your audience is spread across regions.
Practical next step
Pick your largest above-the-fold image, add it to gatsby-source-filesystem, query it with gatsbyImageData, and render it with GatsbyImage. Build the site, inspect srcSet in the output HTML, and confirm WebP or AVIF appears in the Network tab. If the build slows down as your library grows, audit which images are truly needed at build time and move the rest to on-demand loading.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.