How to Configure Next.js Image Sizes
Configure width, height, sizes, deviceSizes, and imageSizes in Next.js so responsive images load the right pixels without layout shifts.
Direct answer: Set width and height to the source image’s intrinsic pixel dimensions. Add sizes whenever CSS or fill makes the rendered width responsive. Configure deviceSizes for viewport-sized candidates and imageSizes for smaller candidates. The sizes value must describe the width the image actually occupies.
The Next.js Image component extends the HTML <img> element for automatic image optimization. Read the official Image component reference for the API details.
1. Choose the right sizing pattern
| Situation | Use | Why |
|---|---|---|
| Known image dimensions | width and height |
Reserves the aspect-ratio box and reduces layout shift. CSS still controls the displayed size. |
| Static import | Import the file | Next.js derives width and height automatically. |
| Remote or dynamic URL | width and height |
Provides the intrinsic aspect ratio when Next.js cannot read a static import. |
| Parent controls the box or the ratio is unknown | fill plus a positioned parent |
The parent defines the image box; sizes tells the browser how wide it will be. |
| CSS-responsive width | Responsive CSS, height: auto, and matching sizes |
Keeps the image proportional while allowing the browser to select an appropriate candidate. |
2. Fixed-size images with width and height
Use the source file’s intrinsic dimensions, not the CSS width you want on screen. For example, if the source file is 1600 by 900 pixels:
import Image from 'next/image'
export default function ProductImage() {
return (
<Image
src="/product.jpg"
alt="Product"
width={1600}
height={900}
/>
)
}
You can then constrain the rendered size with CSS:
.productImage {
width: 320px;
height: auto;
}
width and height describe intrinsic dimensions and reserve aspect-ratio space. They do not force the final CSS-rendered width.
3. Responsive images and the sizes prop
When the image width changes with the viewport, provide sizes. The browser uses it with Next.js’s generated width-based srcset to choose a candidate.
import Image from 'next/image'
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt=""
width={2400}
height={1350}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ width: '100%', height: 'auto' }}
/>
)
}
This expression says the image occupies the full viewport up to 768px, half the viewport up to 1200px, and one third of the viewport above that. Replace those values with the actual layout rules in your CSS.
If you omit sizes, the browser assumes 100vw. That can make it download a larger candidate than the layout needs. With sizes, Next.js generates a fuller width-based srcset; without it, generation is more limited and is better suited to fixed-size images.
4. Full-bleed and parent-controlled images with fill
Use fill when the parent controls the box or the source aspect ratio is unavailable. The parent must be positioned, and sizes should describe the rendered width.
import Image from 'next/image'
export default function Cover() {
return (
<div className="cover">
<Image
src="/cover.jpg"
alt=""
fill
sizes="(max-width: 768px) 100vw, 50vw"
style={{ objectFit: 'cover' }}
/>
</div>
)
}
.cover {
position: relative;
min-height: 320px;
}
@media (min-width: 769px) {
.cover {
min-height: 480px;
}
}
Do not use fill as a substitute for describing layout. The parent dimensions and the sizes expression must agree with the actual design.
5. Static imports versus remote URLs
Static import
import Image from 'next/image'
import hero from '../public/hero.jpg'
export default function Page() {
return <Image src={hero} alt="" />
}
For a static import, Next.js derives the image dimensions automatically.
Remote or dynamic URL
import Image from 'next/image'
export default function Avatar({ url }) {
return (
<Image
src={url}
alt="Profile photo"
width={256}
height={256}
/>
)
}
For a remote or dynamic URL, provide the intrinsic width and height so Next.js can calculate the aspect-ratio box.
6. Configure deviceSizes and imageSizes
Use deviceSizes for viewport breakpoints when the documented defaults do not match your audience or layout. The documented default list is [640, 750, 828, 1080, 1200, 1920, 2048, 3840].
// next.config.js
module.exports = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
}
Use imageSizes for smaller-than-viewport images that provide a sizes prop. The documented default list is [32, 48, 64, 96, 128, 256, 384]. Every imageSizes entry should be smaller than the smallest deviceSizes entry.
// next.config.js
module.exports = {
images: {
imageSizes: [32, 48, 64, 96, 128, 256, 384],
},
}
These arrays are candidate widths, not CSS breakpoints. Keep candidates that cover the widths your users actually receive, and make the array large enough to avoid repeatedly rounding up to a much larger file.
7. A complete responsive card example
import Image from 'next/image'
export default function CardGrid({ posts }) {
return (
<section className="grid">
{posts.map((post) => (
<article key={post.id} className="card">
<Image
src={post.imageUrl}
alt={post.imageAlt}
width={1200}
height={800}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
className="cardImage"
/>
<h2>{post.title}</h2>
</article>
))}
</section>
)
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
}
.cardImage {
display: block;
width: 100%;
height: auto;
}
@media (min-width: 641px) {
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1025px) {
.grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
The sizes value mirrors the three-column, two-column, and one-column CSS layout. If the grid gap, sidebar, or container width changes, update sizes to describe the real image width.
8. How to write a correct sizes expression
- Find the CSS rule that determines the image width at each breakpoint.
- Express that width as a viewport percentage such as
100vw,50vw, or33vw. - Put the narrowest viewport condition first.
- Use a final fallback that matches the widest layout.
- Recheck the expression after changing container widths, sidebars, or grid columns.
| Layout | Example sizes |
|---|---|
| Always full width | 100vw |
| Half width below 900px, one third above | (max-width: 900px) 50vw, 33vw |
| Full width on mobile, half on larger screens | (max-width: 768px) 100vw, 50vw |
9. Troubleshooting
The browser downloads an image that is too large
Cause: sizes is missing or says 100vw when the image occupies less space.
Fix: Measure the rendered width at each breakpoint and make sizes mirror those values.
The image causes layout shift
Cause: The intrinsic aspect ratio is unavailable.
Fix: Add accurate width and height, use a static import, or use fill inside a parent with a defined size.
The image does not fill its container
Cause: The component uses intrinsic sizing instead of fill, or the parent has no usable dimensions.
Fix: Make the parent positioned, give it a height or aspect-ratio, and use fill with a matching sizes value.
The selected candidate is still larger than expected
Cause: The required width falls between configured candidates, so the browser selects the next available width.
Fix: Review deviceSizes and imageSizes. Add useful candidate widths while keeping every imageSizes value below the smallest deviceSizes value.
A dynamic image has no dimensions
Cause: Remote URLs do not provide dimensions through a static import.
Fix: Supply the source image’s intrinsic dimensions explicitly.
10. Performance, reliability, and cost notes
- Accurate dimensions reserve space before the image loads and reduce layout shift.
- A truthful
sizesvalue helps the browser avoid downloading a candidate wider than the rendered image. - Keep candidate arrays aligned with real viewport and component widths. Excessively broad arrays increase configuration complexity; sparse arrays can force rounding up to a larger candidate.
- When CSS changes, review the corresponding
sizesexpression in the same change. - For important pages, inspect the rendered width at mobile, tablet, and desktop sizes and compare it with the selected
srcsetcandidate.
11. Or skip the browser setup
If your task is to create screenshots of pages rather than optimize images inside a Next.js app, ScreenshotNeo provides a single screenshot request. Its API can return PNG, JPEG, WebP, or PDF, and the ScreenshotNeo documentation lists the options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and whether it was billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
12. FAQ
Do width and height set the displayed size?
No. They describe intrinsic dimensions and reserve the aspect-ratio box. CSS determines the rendered size.
When should I use fill?
Use it when the parent controls the image box or the intrinsic aspect ratio is unknown. The parent must be positioned, and responsive layouts need sizes.
What happens when sizes is omitted?
The browser assumes 100vw, which can select an unnecessarily large candidate for a narrower image.
How are deviceSizes and imageSizes different?
deviceSizes contains viewport-oriented widths. imageSizes contains smaller widths for images that use sizes; each should be smaller than the smallest device size.
Should every image use the same sizes value?
No. Each value should describe that component’s actual layout at each breakpoint.


