TL;DR
Next.js が画像の最適化のために提供する <Image> コンポーネント。<img> を拡張したもので、画像形式の変換、レイアウトシフトの防止、遅延読み込みなどを自動で行う。
なぜ必要か
画像は Largest Contentful Paint のスコアに直結する。<Image> は次の最適化を自動で行う。
仕組み
キャッシュ
最適化した画像はサーバが初回のリクエストで作り、.next/cache/images にキャッシュする。そのため初回だけ遅い。キャッシュは Time-based Revalidation と同じく Stale-While-Revalidate の挙動になる。状態は x-nextjs-cache ヘッダの MISS、STALE(TTL 切れで更新中)、HIT で分かる。
TTL はデフォルトで無期限で、minimumCacheTTL で変えられる。画像ごとに変えるには Cache-Control の max-age を使う。両方あれば大きい方が使われる。
画像形式の選択
Accept ヘッダでブラウザが対応する形式を調べ、images.formats(デフォルトは ['image/webp'])と最初に一致した形式を使う。一致しなければ元の形式のままになる。
例
ローカル画像は import して src に渡す。width と height はビルド時に決まるので省略できる。
import Image from "next/image"
import profilePic from "./me.png"
export default function Page() {
return <Image src={profilePic} alt="Picture of the author" priority />
}リモート画像は width と height が必須になる。サイズは import、width と height、fill のいずれかで決める。
LCP 要素の画像に priority を付けると優先して読み込まれる。付けていないと、開発環境で警告が出る。
注意点
altは必須である。ただし装飾目的の画像では空文字を指定する- 悪意のある SVG などを防ぐため、リモート画像は
images.remotePatternsで許可したホストからしか読み込めない - 前段にプロキシや CDN を置くときは、
Acceptヘッダを転送する - Next.js 15 の時点では画像のキャッシュを無効にできない。
minimumCacheTTLを小さくする、srcにクエリパラメータを付ける、キャッシュを消す、などで回避する
自分の理解
画像ごとに Cache-Control を指定したいなら、ミドルウェアで付けると良さそうだ。