Gatsby Static Assets and Images — File Handling in Gatsby
Learn how to handle static assets, images, fonts, and other files in Gatsby projects for optimal performance and build efficiency.
In this lesson, you'll understand how Gatsby processes files from the static/ directory and the src/ directory, and when to use each approach.
What You'll Learn
How to serve static files from the static/ directory, import assets from src/, optimize images, and handle fonts and PDFs.
Why It Matters
Proper asset handling affects both development workflow and production performance. Static files should be cached, optimized, and served efficiently.
flowchart LR
A[Assets] --> B[static/ folder]
A --> C[src/ imports]
B --> D[Served as-is]
B --> E[Known URL]
C --> F[Webpack Processed]
C --> G[Hash Fingerprinted]
C --> H[Optimized]
style A fill:#639,color:#fff
style B fill:#4a148c,color:#fff
The static/ Folder
Files in static/ are copied to the build output as-is:
static/
├── favicon.ico
├── robots.txt
├── CNAME
├── fonts/
│ └── custom-font.woff2
└── downloads/
└── guide.pdf
Reference them with absolute paths:
import React from 'react';
function Favicon() {
return <link rel="icon" href="/favicon.ico" />;
}
function DownloadLink() {
return <a href="/downloads/guide.pdf">Download Guide</a>;
}
Output: Files in static/ are served at the root URL. /favicon.ico becomes /favicon.ico in the built site.
Importing Assets from src/
Assets imported from src/ are processed by webpack:
import React from 'react';
import logo from '../images/logo.svg';
import heroImage from '../images/hero.jpg';
function Header() {
return (
<header>
<img src={logo} alt="Logo" />
<img src={heroImage} alt="Hero" />
</header>
);
}
Output: Webpack processes imported assets: SVGs may be inlined, images are optimized, and filenames get content hashes for cache busting.
Image Optimization
Use gatsby-plugin-image for optimized images:
npm install gatsby-plugin-image gatsby-plugin-sharp gatsby-transformer-sharp gatsby-source-filesystem
import { graphql } from 'gatsby';
import { GatsbyImage, getImage } from 'gatsby-plugin-image';
import React from 'react';
function Hero({ data }) {
const image = getImage(data.file.childImageSharp.gatsbyImageData);
return (
<GatsbyImage
image={image}
alt="Hero background"
loading="lazy"
/>
);
}
export const query = graphql`
query {
file(relativePath: { eq: "hero.jpg" }) {
childImageSharp {
gatsbyImageData(
width: 1200
placeholder: BLURRED
formats: [AVIF, WEBP, AUTO]
)
}
}
}
`;
Output: The image is automatically optimized: resized to 1200px, converted to AVIF/WebP, with a blurred placeholder. Only the optimal format is loaded.
Font Handling
Self-host fonts for performance:
static/fonts/
├── inter-v12-latin-regular.woff2
└── inter-v12-latin-700.woff2
/* src/styles/fonts.css */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-v12-latin-regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-v12-latin-700.woff2') format('woff2');
font-weight: 700;
font-display: swap;
}
Output: Fonts are served from your own domain, avoiding third-party DNS lookups. font-display: swap ensures text remains visible during font loading.
PDFs and Other Files
Handle non-image files in GraphQL:
export const query = graphql`
query {
allFile(filter: { extension: { eq: "pdf" } }) {
edges {
node {
publicURL
name
size
}
}
}
}
`
function DownloadList({ data }) {
return (
<ul>
{data.allFile.edges.map(({ node }) => (
<li key={node.publicURL}>
<a href={node.publicURL}>{node.name}</a>
<span>({(node.size / 1024).toFixed(0)} KB)</span>
</li>
))}
</ul>
);
}
Output: All PDF files in sourced directories are listed with download links and file sizes.
Common Mistakes
- Putting files in
static/that should be processed: If an asset needs optimization or hashing, import it fromsrc/instead of putting it instatic/. - Using absolute paths incorrectly in CSS: CSS background images using
url()from CSS Modules need different resolution. Use webpack's~prefix or import in JS. - Not using
gatsby-plugin-imagefor images: Without it, images are unoptimized: no Lazy Loading, no responsive sizes, no modern formats. - Putting too many files in
static/: Every file instatic/increases build time. Only put files here that shouldn't be processed. - Linking to non-existent static files: Reference files in
static/with leading slash:/fonts/font.woff2. No relative paths.
Practice Questions
What is the difference between files in
static/and imported fromsrc/? Answer:static/files are copied as-is.src/imports are processed by webpack (optimized, hashed, inlined).How do you reference a file in
static/? Answer: Use an absolute path:src="/filename.pdf". The file is served at the root URL.What does
gatsby-plugin-imageprovide? Answer: Optimized images with lazy loading, responsive sizes, modern formats (AVIF, WebP), and blurred placeholders.Why use
font-display: swap? Answer: It displays text immediately with a fallback font while the custom font loads, preventing invisible text (FOIT).
Challenge
Build a hero section with a background image using gatsby-plugin-image. Add a custom font using font-display: swap. Include a downloadable PDF brochure. Verify all assets load correctly in production build.
Mini Project
Create a gallery page with 10+ optimized images using gatsby-plugin-image. Display them in a responsive grid with lazy loading and AVIF/WebP format support.
FAQ
What's Next
Learn about Gatsby Image Plugin for deep coverage of gatsby-plugin-image, fluid and fixed images, and advanced image techniques.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro