How to Use the Next.js Image Component for Optimized Images
Use next/image with the right dimensions, responsive sizes, loading behavior, and remote image rules. Includes runnable examples and fixes for common errors.
next/image is Next.js’s image component for automatic image optimization. Import it from next/image, provide descriptive alt text, and choose dimensions or fill to match the layout. Add an accurate sizes value for responsive images, keep ordinary images lazy-loaded, and prioritize only the image likely to be the page’s Largest Contentful Paint (LCP) element. For remote files, allow only the required sources with remotePatterns.
The examples below follow the official Next.js Image Component reference. Check the docs for your installed Next.js version: the reference says priority is deprecated in Next.js 16 in favor of preload.
1. Start with a local image
Put the file in public/, then use its path from the site root. Give the image intrinsic dimensions so the browser can reserve its aspect ratio before it loads. CSS controls the rendered size; the width and height props describe the image’s intrinsic dimensions.
import Image from 'next/image'
export default function Profile() {
return (
<Image
src="/profile.png"
width={640}
height={640}
alt="Portrait of the account owner"
/>
)
}
A static import is also supported. With a supported static JPG, PNG, WebP, or AVIF asset, Next.js can supply blur data automatically unless the image is animated:
import Image from 'next/image'
import portrait from './portrait.jpg'
export default function Profile() {
return <Image src={portrait} alt="Portrait of the account owner" />
}
Write alt text that could replace the image without changing the page’s meaning. If an image is purely decorative, use alt="". Don’t use alt text to repeat an adjacent caption.
2. Choose intrinsic dimensions or a fill layout
| Choose | When it fits | What to set |
|---|---|---|
width and height |
The image has a known aspect ratio and its own place in the layout. | Both values, unless the source is statically imported. |
fill |
The image should follow a container’s dimensions, such as a card thumbnail or hero crop. | A positioned parent, plus image sizing and crop styles. |
For fill, the parent must use position: relative, absolute, or fixed. Give the parent an actual size, and use object-fit: cover when cropping is intended or contain when the whole image must remain visible.
import Image from 'next/image'
export default function ProductCard() {
return (
<div className="product-image">
<Image
src="/chair.jpg"
alt="Oak chair with a woven seat"
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
style={{ objectFit: 'cover' }}
/>
</div>
)
}
/* In a global stylesheet or CSS module */
.product-image {
position: relative;
aspect-ratio: 4 / 3;
overflow: hidden;
}
The aspect ratio (or another explicit height) prevents a zero-height container. With cover, some edges may be cropped; adjust the crop with objectPosition if the subject needs to sit off-center.
3. Make responsive image selection accurate
The sizes prop tells the browser how wide the image is expected to render at different viewport widths. The browser uses that hint to choose from the generated srcset. Write it to match your actual CSS layout, including grid gaps or a max-width container where relevant.
<Image
src="/team.jpg"
alt="The team gathered around a worktable"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ objectFit: 'cover' }}
/>
Use sizes whenever the image uses fill or CSS makes it responsive. Without it, the browser assumes the image is as wide as the viewport, which can result in downloading a larger candidate than the layout needs. With sizes, Next.js generates a width-based srcset; without it, the generated set is more limited and better suited to fixed-size images.
For example, if a card spans the viewport on small screens and one third of the content width on large screens, a value like (max-width: 768px) 100vw, 33vw is a starting shape. Change the breakpoints and widths to reflect the real layout, then inspect the rendered image’s currentSrc and dimensions in browser developer tools.
4. Load the important image without delaying it
Images are lazy-loaded by default. Keep that default for images below the fold. For an image that must start immediately, choose loading="eager" or fetchPriority="high" selectively. Reserve preload for the single image that is genuinely likely to be the LCP element, usually an above-the-fold hero.
import Image from 'next/image'
export default function LandingHero() {
return (
<Image
src="/hero.jpg"
alt="A mountain lodge beside a lake at sunrise"
width={1800}
height={1100}
sizes="100vw"
preload
/>
)
}
Do not preload several competing images. The reference advises against combining preload with loading or fetchPriority. In Next.js 16, use preload instead of the deprecated priority prop. In earlier versions, follow that version’s documentation and avoid copying a prop that your installed version does not support.
5. Allow remote images safely
An absolute external URL needs a matching remotePatterns entry. Restrict the protocol, hostname, path, and—when useful—the query string to what the application needs. Unspecified pattern fields can act as wildcards; broad rules permit URLs beyond the intended image source.
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.example.com',
port: '',
pathname: '/products/**',
search: '',
},
],
},
}
module.exports = nextConfig
Then use an allowed URL:
import Image from 'next/image'
export default function ProductPhoto() {
return (
<Image
src="https://images.example.com/products/lamp.jpg"
alt="Brass desk lamp with a green shade"
width={1200}
height={900}
/>
)
}
Restart the development server after changing configuration. If the source uses variable query strings, decide which query parameters are required and configure the pattern accordingly; don’t remove restrictions automatically just to make an error disappear. The older domains setting is deprecated since Next.js 14 and cannot restrict protocol, port, or pathname, so prefer remotePatterns.
6. Configure local paths and image quality
Use localPatterns when the app should optimize only a defined subset of local paths. An image path outside the allowed pattern can return a 400 response.
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
localPatterns: [
{
pathname: '/assets/images/**',
search: '',
},
],
},
}
module.exports = nextConfig
The quality prop accepts an integer from 1 to 100. Higher values can increase file size; lower values can reduce sharpness. The default is 75. If you configure the qualities allowlist, values outside it are coerced to the nearest allowed value; development logs a warning. Tune quality against the actual source: a higher setting cannot restore detail missing from a low-quality original.
<Image
src="/catalog.jpg"
alt="Blue ceramic bowl on a wooden table"
width={1200}
height={900}
quality={75}
/>
7. Use blur placeholders and styling deliberately
Set placeholder="blur" with a blurDataURL for remote or dynamically selected images. Keep the data URL small; embedding a large placeholder adds page data. Supported static imports can provide the blur data automatically when applicable.
<Image
src="https://images.example.com/products/lamp.jpg"
alt="Brass desk lamp with a green shade"
width={1200}
height={900}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,SMALL_BLUR_DATA_HERE"
/>
For normal responsive styling, use CSS classes or the style prop. If you set a custom width directly in styles, also set height: 'auto' to preserve the aspect ratio. Use object-fit for filled containers instead of allowing an image to stretch.
8. Handle SVG, authenticated sources, and custom delivery
- SVG: SVG is not optimized by default. For a known SVG source, use
unoptimizedwhen appropriate. If enabling SVG serving in configuration, the Next.js docs recommend attachment disposition and a restrictive content security policy. - Authenticated source images: the default optimizer does not forward authentication headers to the source. Consider
unoptimizedor an image delivery architecture that can access the asset without forwarding browser credentials through the optimizer. Don’t expose private images through a public URL. - Custom image service: the
loaderprop orloaderFileconfiguration can generate URLs for an external image transformation service. The loader receives the source, target width, and quality and returns a URL. Choose this when your delivery setup requires transformations outside the built-in optimizer.
For example, a component-level loader can build a URL for a service you control:
const imageLoader = ({ src, width, quality }) =>
`https://images.example.com/${src}?w=${width}&q=${quality || 75}`
<Image
loader={imageLoader}
src="catalog/lamp.jpg"
alt="Brass desk lamp with a green shade"
width={1200}
height={900}
/>
A loader function is a function prop, so use it in a Client Component when required by the component boundary. For an app-wide loader, configure loaderFile as documented for your Next.js version.
9. DIY checklist for production
- Use
Imagefromnext/imageand provide meaningfulalttext (or an empty string for decoration). - Use both intrinsic dimensions for known-aspect images, or use
fillinside a positioned parent with a defined size. - Add a
sizesexpression that mirrors responsive CSS, especially forfill. - Leave offscreen images lazy-loaded. Prioritize only the likely LCP image.
- Allow remote URLs with a narrow
remotePatternsrule; constrain local paths withlocalPatternsif useful. - Check any query-string, SVG, authentication, and image-quality constraints against your source and installed Next.js version.
- Inspect layout shift, selected
currentSrc, image requests, and console warnings at representative viewport widths.
10. Or skip the browser setup
If you need screenshots of the rendered page while checking image layouts, [ScreenshotNeo](https://screenshotneo.com) is a website screenshot API and MCP server. Its one-call API can return a screenshot or PDF; use the screenshot call below and see the ScreenshotNeo API docs for 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, popups, and chat widgets are removed before the shot.
- Bot checks, blank pages, and failed loads are never billed.
- An MCP server lets AI agents use screenshot tools.
- 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.
Sign up for 1,000 free screenshots a month, with no card required.
11. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Remote image request returns 400. | The URL does not match remotePatterns, including its protocol, hostname, path, port, or search string. |
Compare the full source URL with the configured pattern, narrow or correct the intended rule, and restart the dev server after config changes. |
| Local image request returns 400. | The path is excluded by localPatterns. |
Allow the intended local path, keeping the pattern limited to paths your app uses. |
| Image appears stretched or the fill container is empty. | The parent has no positioned layout or usable height; default sizing can stretch the image. | Set parent positioning and dimensions or an aspect ratio. Use objectFit: 'cover' or 'contain'. |
| Responsive page downloads a very large image. | sizes is missing or claims the image is wider than the CSS layout. |
Set sizes for the actual rendered width at each breakpoint and inspect the chosen currentSrc. |
| Hero image appears late. | The important image remains lazy-loaded or competes with many preloads. | Use eager loading or high fetch priority selectively; preload only the likely LCP image. Check that the browser can discover its URL early. |
| Blur placeholder errors or is missing. | placeholder="blur" lacks usable blur data for a remote/dynamic source. |
Supply a small blurDataURL, or remove the blur placeholder. |
| Authenticated image fails through optimization. | The default optimizer does not forward source authentication headers. | Use an appropriate authenticated delivery path or consider unoptimized after reviewing exposure and caching implications. |
| Quality warning or unexpected output quality. | The requested quality is not in the configured allowlist. |
Use an allowed quality value or update qualities to include the deliberate value. |
12. Performance, reliability, and cost notes
Correct dimensions reserve space and reduce layout shift. Accurate sizes prevents oversized responsive downloads. Lazy loading avoids fetching ordinary below-the-fold images immediately, while selective priority helps the browser start on the likely LCP image. These settings guide browser and optimizer behavior; they do not guarantee a particular page speed because source size, network conditions, rendering, and deployment also matter.
Keep remote allowlists narrow to limit which resources the optimizer can fetch. Remember that remote source headers are not forwarded, and account for source availability and authentication in your delivery design. The Next.js documentation describes a default maximum optimizer response body of 50 MB; check the current version’s configuration when serving large source files. Optimized image processing and delivery consume resources in the deployment environment or image service you choose, so avoid generating many unnecessary size and quality variants. No fixed cost or performance benchmark applies across deployments.
13. FAQ
Do I need to replace every HTML image with next/image?
No. Use it where its optimization, responsive selection, or layout benefits fit. For SVGs or sources that need direct delivery, assess unoptimized and the security implications first.
Can I use a remote URL without editing Next.js configuration?
The default optimizer requires remote sources to match an allowed remote pattern. Add a specific remotePatterns entry for the source.
Should every above-the-fold image be preloaded?
No. Preload the image likely to be the LCP element. Several competing preloads can consume bandwidth without helping the browser identify the most important image.
Where can I check version-specific prop behavior?
Use the official Image Component reference and match it to your installed Next.js version, especially for loading priority and configuration options.


