This episode covers image optimization in Gatsby: gatsby-plugin-image for responsive images, configuring gatsby-plugin-sharp and gatsby-transformer-sharp, lazy loading and placeholders, and handling audio and video on pages.

Images are the biggest contributor to a web page's weight. Gatsby solves this with the Sharp plugin suite, which generates responsive images automatically: modern formats, the right size for every screen, lazy loading, and smooth placeholders.
Episode 6 breaks down gatsby-plugin-image, its two main components, the configuration of supporting plugins, and how to handle other media such as audio and video.
gatsby-plugin-image works together with Sharp. Install all four packages at once:
npm install gatsby-plugin-image gatsby-plugin-sharp
npm install gatsby-transformer-sharp gatsby-source-filesystemThen register them in gatsby-config.js:
module.exports = {
plugins: [
"gatsby-plugin-image",
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
{
resolve: "gatsby-source-filesystem",
options: {
name: "images",
path: `${__dirname}/src/images`,
},
},
],
}The first three plugins work together: the filesystem source provides files, transformer-sharp turns images into nodes, and plugin-image provides the gatsbyImageData field ready to render.
For images whose location is fixed (for example, logos and illustrations), use StaticImage without a query:
import { StaticImage } from "gatsby-plugin-image"
const Hero = () => (
<StaticImage
src="../images/hero.png"
alt="Ilustrasi hero"
width={1200}
placeholder="blurred"
/>
)<StaticImage src="../images/hero.png" alt="Ilustrasi hero"{:jsx}> requires the path to be resolved at build time. The width and layout props control the responsive sizes that are generated.
For dynamic images — for instance, the image from each post's frontmatter — query the image and then render it with GatsbyImage:
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
export const query = graphql`
query {
markdownRemark {
frontmatter {
featuredImage {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH, placeholder: BLURRED)
}
}
}
}
}
`
const PostPage = ({ data }) => {
const image = getImage(data.markdownRemark.frontmatter.featuredImage)
return (
<GatsbyImage
image={image}
alt="Gambar utama post"
/>
)
}The helper getImage turns an image node into an object that GatsbyImage can use. layout: FULL_WIDTH makes the image stretch to the full width of its container.
Choose the layout that fits your needs:
FIXED: a fixed size, suitable for avatars and icons.CONSTRAINED: a maximum size that shrinks on smaller screens.FULL_WIDTH: the full width of its container, used for heroes and banners.Gatsby automatically picks the best format between WebP and AVIF, then uses a source set for every screen resolution. Quality can be tuned with query arguments such as quality: 80 and transformOptions for cropping.
The blurred placeholder shows a small, blurry version while the real image loads. For images outside the viewport, Gatsby uses Intersection Observer so only visible images are loaded — that's the built-in lazy loading.
Tip
Always fill the alt property with a meaningful description. Decorative images may use an empty alt="", but don't remove it entirely because that hurts accessibility.
Gatsby doesn't transcode video automatically; large media files should be placed in the static folder or an external CDN, then rendered with standard HTML elements:
const MediaSection = () => (
<section>
<video controls preload="none" poster="../images/cover.png">
<source src="/video/demo.mp4" type="video/mp4" />
</video>
<audio controls preload="metadata">
<source src="/audio/episode.mp3" type="audio/mpeg" />
</audio>
</section>
)The preload="none" attribute on the video prevents data from downloading before playback. For embeds from external services like YouTube, a standard iframe works just fine.
The static folder at the project root is copied as-is to public at build time. Put files that don't need data-layer processing there, so their URLs are directly accessible, like /video/demo.mp4.
Episode 6 completed media optimization: gatsby-plugin-image and Sharp for responsive images, StaticImage for static images, GatsbyImage for images from queries, and handling audio and video.
Key takeaways:
StaticImage for images with a fixed path; GatsbyImage for images from GraphQL.static folder or a CDN.alt attribute for accessibility.In the next episode, episode 7, we'll discuss plugins and themes — understanding the Gatsby plugin ecosystem, how to install and configure them, building reusable themes, and best practices for plugin ordering and their impact on performance.