Course
Image I
Next.js Mastery: From Fundamentals to Full-Stack
Unlock the power of Next.js with this comprehensive course! Starting with the basics, you’ll learn essential skills such as routing, data fetching, and styling. Progress through practical projects, including building your own React Notes app, to gain hands-on experience. Dive into the source code to understand the inner workings and core principles of Next.js. Perfect for developers with a basic knowledge of React and Node.js, this course ensures you’ll be ready to create high-performance full-stack applications efficiently. Join us and master Next.js, backed by industry experts and a supportive learning community.
Image
1. Feature Highlights
Explaining LCP (Largest Contentful Paint) is just to help everyone understand the importance of image optimization (since the largest content element is often an image). Moving on to the
<Image>
component, Next.js builds on the native HTML <img>
element to implement these optimization features:- Size Optimization: Automatically provides the correct size image for each device and uses modern image formats like WebP and AVIF.
- Visual Stability: Prevents layout shifts during image loading.
- Faster Page Load: Images only load when they enter the viewport, using lazy loading with an optional blur placeholder.
- Flexible Configuration: Allows on-demand image adjustments, including support for images from remote servers.
We'll cover these features one by one when explaining the component API.
2. Basic Usage
Here’s an example of using the
<Image>
component. It looks just like using a normal <img>
element:// app/page.jsimport Image from 'next/image'
export default function Page() { return ( <Image src="/profile.png" width={500} height={500} alt="Picture of the author" /> )}
3. Supported Props
The
<Image>
component supports these props: Among these,
src
, width
, height
, and alt
are required. Let's go through them one by one.4. src - Required
The
src
prop supports passing in a static image file or a string path.When using a local image, you can statically import the image file. Import files in
.jpg
, .png
, or .webp
formats using import
. Here’s an example:// app/page.jsimport Image from 'next/image'import profilePic from './me.png'
export default function Page() { return ( <Image src={profilePic} alt="Picture of the author" // width={500} automatically provided // height={500} automatically provided // blurDataURL="data:..." automatically provided // placeholder="blur" // Optional blur-up while loading /> )}
When using static file import,
width
and height
are not required, as Next.js will automatically provide them.Note: Dynamicawait import()
orrequire()
is not supported. The import must be static for analysis during the build. When using remote images,src
can accept a URL string.
Since Next.js cannot fetch remote files during the build, you need to manually provide the
width
, height
, and optionally, the blurDataURL
props.The
width
and height
attributes help infer the correct aspect ratio and avoid layout shifts during image loading. However, width
and height
do not determine the final rendered size, which makes sense since you might set stretching modes, etc.// app/page.jsimport Image from 'next/image'
export default function Page() { return ( <Image src="https://s3.amazonaws.com/my-bucket/profile.png" alt="Picture of the author" width={500} height={500} /> )}
When using remote URLs, Next.js requires defining supported remote image URLs in the
next.config.js
file to prevent malicious usage. Here's how to configure it:// next.config.jsmodule.exports = { images: { remotePatterns: [ { protocol: 'https', hostname: 's3.amazonaws.com', port: '', pathname: '/my-bucket/**', }, ], },}
We'll explain
remotePatterns
in detail later in this article.5. width - Required
The
width
attribute indicates the rendered width of the image in pixels, affecting its display size.This attribute is required unless the image is statically imported or has the
fill
attribute.6. height - Required
The
height
attribute indicates the rendered height of the image in pixels, affecting its display size.This attribute is required unless the image is statically imported or has the
fill
attribute.7. alt
The
alt
attribute is used to describe the image, providing information to screen readers and search engines. If the image is disabled or an error occurs during loading, it serves as fallback text.The
alt
attribute should provide a text description that replaces the image without changing the meaning of the page. It should not repeat information provided in captions above or below the image.If the image is purely decorative or not intended for user interaction, the
alt
attribute should be an empty string (alt=""
).8. loader
The
loader
prop represents a custom function for resolving image URLs. Let’s look at an example:'use client'
import Image from 'next/image'
const imageLoader = ({ src, width, quality }) => { return `https://example.com/${src}?w=${width}&q=${quality || 75}`}
export default function Page() { return ( <Image loader={imageLoader} src="me.png" alt="Picture of the author" width={500} height={500} /> )}
The function takes
src
, width
, and quality
as parameters and returns the image URL string.Note: Since theloader
prop is passed a function, you need to use a client component. In this example, the top line uses'use client'
.
Adding a
loader
to every image can be cumbersome, so you can configure the loaderFile
option in next.config.js
to apply to every next/image
instance without needing to pass the loader
prop. We’ll explain this configuration option later in the article.9. fill
fill={true} // {true} | {false}
The
fill
prop indicates whether the image should fill its parent element. The default value is false
. This is useful when the image’s width
and height
are unknown.However, note that when using
fill
, the parent element must be set to position: "relative"
, position: "fixed"
, or position: "absolute"
. The <img>
element will automatically be set to position: "absolute"
by default.If no other styles are applied, the image will be stretched to fill the container.
There are many ways to fill a container. The CSS property
object-fit: "contain"
or object-fit: "cover"
can also be used to fill the image.Let’s look at a simple example:
// app/page.jsimport Image from 'next/image'import profilePic from './image.png'
export default function Page() { return ( <div style={{ width: '200px', height: '200px', backgroundColor: "#ccc", position: 'relative' }}> <Image src={profilePic} alt="Picture of the author" /> </div> )}
The normal display looks like this:
If the
fill
prop is added:<Image src={profilePic} alt="Picture of the author" fill={true}/>
The result will look like this, with the image stretched to fit the container:
If you use
object-fit: "contain"
:<Image src={profilePic} alt="Picture of the author" fill={true} style={{objectFit: "contain"}}/>
The result will be as follows, with the image filling the entire content box while maintaining its aspect ratio:
If you use
object-fit: "cover"
:<Image src={profilePic} alt="Picture of the author" fill={true} style={{objectFit: "cover"}}/>
The result will be as follows, with the image filling the entire content box while maintaining its aspect ratio. If the aspect ratio of the object does not match the content box, the object will be cropped to fit the content box:
10. sizes
HTML 5.1 introduced the
srcset
and sizes
attributes for the <img>
element to set responsive images.When we need to display different images on different devices, we use
srcset
. There are two specific scenarios: the image has the same dimensions but different resolutions for different images, i.e., higher resolution images for higher pixel densities; or the same image content is displayed larger or smaller based on the device. These correspond to the two syntaxes of srcset
.First, let’s discuss the first scenario, where different images are displayed based on different resolutions. Here’s an example:
<img srcset="elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x" src="elva-fairy-640w.jpg" alt="Elva dressed as a fairy"
/>
The result looks like this:
srcset
is a comma-separated list of one or more strings, each composed of:- A URL pointing to the image
- A space (optional)
- A pixel density descriptor (a positive floating-point number followed by the
x
symbol)
If we apply a CSS style to the image:
img { width: 320px;}
Its width on the screen will be 320 pixels (CSS pixels). The browser calculates the resolution of the display and displays the most appropriate image from the
srcset
. If it’s a normal resolution, where one device pixel equals one CSS pixel, it loads elva-fairy-320w.jpg
, which is 39KB. If the device has a high pixel density, where two or more device pixels equal one CSS pixel, it loads elva-fairy-640w.jpg
, which is 93KB.Now, let’s discuss the second scenario, where the same image content is displayed larger or smaller based on the device. Here’s an example:
<img srcset="elva-fairy-small.jpg 480w, elva-fairy-large.jpg 800w" src="elva-fairy-large.jpg" alt="Elva dressed as a fairy" />
The syntax of
srcset
is slightly different from the previous example. It defines a set of images that the browser can choose from, along with the size of each image. Analyzing the syntax, it is still a comma-separated list of one or more strings, each composed of:- A URL pointing to the image
- A space
- The intrinsic width of the image (in pixels). Note that here we use the width descriptor
w
, notpx
. But 1w
corresponds to 1 pixel. The intrinsic width of the image refers to its actual size.
This tells the browser that two alternative images are available for display, one is
elva-fairy-small.jpg
with a width of 480px, and the other is elva-fairy-large.jpg
with a width of 800px.How does the browser know which image to use? For example, if the device viewport width is 640px, should it choose the 480px image or the 800px image?
To help the browser decide, you need to use the
sizes
attribute. The sizes
attribute is a set of media query conditions that tell the browser which image to use under what conditions. Here’s an example:<img srcset="elva-fairy-small.jpg 480w, elva-fairy-large.jpg 800w" sizes="(max-width: 600px) 480px, 800px" src="elva-fairy-large.jpg" alt="Elva dressed as a fairy" />
sizes
is a comma-separated list of one or more strings, each composed of:- A media condition, in this example
(max-width:600px)
, which means when the viewport width is less than or equal to 600px. - A space
- The slot size the image will fill when the media condition is true. This width can be a fixed value, like 480px in this example, or a relative width to the viewport (like 50vw), but it cannot be a percentage. If there is no media condition, it applies by default. Once the browser matches the first media condition, all remaining conditions are ignored, so order matters.
With these attributes, the browser will:
- Check the device width.
- Check which media condition in the
sizes
list is true first. - Determine the slot size given by that media query.
- Load the image from the
srcset
list that most closely matches the selected slot size.
For example, in this case, if the browser’s viewport is 480px, the first condition
(max-width: 600px)
in sizes
is true, so it selects the 480px size, and since 480px matches the 480w intrinsic width in srcset
, it loads elva-fairy-small.jpg
. This way, smaller images load on mobile devices, speeding up load times.After explaining the
srcset
and sizes
attributes for the <img>
element, let’s return to the <Image>
component. With Next.js, you don’t need to set srcset
as it will be generated automatically for you. Setting the sizes
attribute affects the generated srcset
values.If you don’t set the
sizes
attribute in the component, Next.js will use pixel density descriptors like 1x
, 2x
. But if you set the sizes
attribute, Next.js will use intrinsic width descriptors like 640w
, 750w
.Before Setting:
After Setting: