Images & Fonts
Automatic optimization for faster visual loading
Pro Tip
Use next/image
and next/font
for automatic optimization. These components handle format selection, lazy loading, and layout stability without manual configuration.
Image Optimization
Images account for 50-70% of page weight. The Next.js Image component automatically optimizes format, size, and loading behavior.
The Next.js Image component handles these concerns automatically:
Format Optimization
Serves WebP or AVIF to modern browsers with automatic fallbacks
Responsive Sizing
Generates multiple resolutions and serves the appropriate size per device
Lazy Loading
Defers off-screen images until users scroll, reducing initial payload
Layout Stability
Reserves space to prevent cumulative layout shift (CLS)
Implementing Next.js Image
Replace standard <img>
tags with the Next.js Image component:
import Image from 'next/image';
export function ProductCard({ product }) {
return (
<Image
src={product.imageUrl}
alt={product.name}
width={400}
height={300}
className="rounded-lg"
/>
);
}
This automatically:
- Generates multiple sizes (1x, 2x)
- Converts to WebP/AVIF
- Lazy loads when off-screen
- Prevents layout shift
export function ProductCard({ product }) {
return (
<img
src={product.imageUrl}
alt={product.name}
className="rounded-lg"
/>
);
}
Standard HTML images:
- Load original format and size
- Block parsing until loaded
- Cause layout shifts
- Download immediately regardless of viewport position
Always specify dimensions
Width and height attributes prevent layout shifts. Next.js uses these values to reserve space before the image loads.
Responsive Images with Sizes
The sizes
prop tells Next.js which image resolution to generate for different viewports:
<Image
src="/hero-banner.jpg"
alt="Product showcase"
fill
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw"
className="object-cover"
/>
This configuration generates:
- Mobile (≤768px): Full viewport width
- Tablet (≤1200px): 50% viewport width
- Desktop (>1200px): 33% viewport width
Next.js generates appropriately sized images for each breakpoint. Mobile users download smaller files, reducing bandwidth consumption and improving load times.
Use fill for unknown dimensions
When image dimensions aren't known at build time (user uploads, CMS content), use the fill
prop with a positioned parent container.
Remote Image Patterns
Applications often load images from external sources. The framework requires explicit configuration for security:
images: {
remotePatterns: [
{ protocol: "https", hostname: "lh3.googleusercontent.com" },
{ protocol: "https", hostname: "avatars.githubusercontent.com" },
{ protocol: "https", hostname: "secure.gravatar.com" },
],
}
This configuration exists in both apps. It allows optimization for:
Security consideration
Only add trusted domains. Remote patterns allow Next.js to proxy and cache images from these sources. Untrusted domains could consume server resources.
Priority Loading for Above-Fold Content
Critical images should load immediately rather than waiting for lazy load thresholds:
<Image
src="/hero-banner.jpg"
alt="Welcome"
width={1200}
height={600}
priority
/>
The priority
prop:
- Preloads the image in
<head>
- Disables lazy loading
- Ensures above-fold images appear instantly
- Should only apply to content visible on initial page load
Limit priority images
Only use priority
for 1-2 images per page. Excessive preloading defeats the purpose of optimization.
Font Optimization
Web fonts cause layout shifts when they load after content renders. Next.js font optimization eliminates this problem through automatic font subsetting and preloading.
Google Fonts Integration
The framework includes built-in Google Fonts support:
import { Inter, Roboto_Mono } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
});
const robotoMono = Roboto_Mono({
subsets: ['latin'],
display: 'swap',
variable: '--font-mono',
});
export default function RootLayout({ children }) {
return (
<html className={`${inter.variable} ${robotoMono.variable}`}>
<body>{children}</body>
</html>
);
}
This configuration:
Downloads fonts at build time
Next.js fetches font files during build and self-hosts them. No runtime requests to Google Fonts CDN.
Subsets the font files
Only includes characters for specified subsets (latin, cyrillic, etc.), reducing file size.
Preloads critical fonts
Adds <link rel="preload">
for instant availability. Prevents flash of unstyled text (FOUT).
Applies CSS variables
Use variables in Tailwind config: fontFamily: { sans: ['var(--font-inter)'] }
Local Font Files
For custom fonts, use the localFont
helper:
import localFont from 'next/font/local';
const customFont = localFont({
src: [
{
path: './fonts/custom-regular.woff2',
weight: '400',
style: 'normal',
},
{
path: './fonts/custom-bold.woff2',
weight: '700',
style: 'normal',
},
],
variable: '--font-custom',
});
Font Display Strategies
The display
property controls font loading behavior:
Font display strategies:
Strategy | Behavior | Use Case |
---|---|---|
swap | Show fallback immediately, swap when font loads | Best for most cases - prevents invisible text |
optional | Use fallback if font doesn't load quickly | Prevents layout shifts, may not load custom font |
block | Hide text until font loads (max 3s) | Use sparingly - creates invisible text |
fallback | Brief invisible period, then show fallback | Balanced between swap and block |
Avoid font-display: block
Blocking text renders creates poor user experience. Users see blank spaces where content should appear. Use swap
or optional
instead.
Measuring Asset Performance
Track asset optimization impact through Core Web Vitals: