Next.jsでoutput: 'export'を指定すると、next/imageの既定ローダーによる画像最適化は使えません。その穴を埋めるのが next-export-optimize-images と next-image-export-optimizer です。どちらもビルド時に変換済み画像を書き出しますが、Next.js 16で同じように動くわけではありません。2026年10月26日に、Next.js 16.4.3(npmの安定版)の検証用プロジェクトで両方をビルドして、出力された画像ファイルとHTMLを突き合わせました。本記事のビルド結果・生成ファイル数・処理時間はこの検証によるもので、環境はmacOS・Node.js 26.5.0・npm 11.17.0です。ダウンロード数・star数・issue数は、比較表に示した外部統計です。
まとめ
- Next.js 16で静的エクスポートするなら next-image-export-optimizer 1.21.2 を選びます。既定のTurbopackビルドのまま、静的インポート画像も
public配下の画像もWebPに変換されました。 - next-export-optimize-images 4.7.0 は Next.js 16 に未対応です。npmでのインストールはERESOLVEで止まり、回避して入れても既定のビルドでは静的インポート画像のsrcsetが存在しないファイルを指します。
next build --webpackなら変換されます。 - 素の
next/imageのままoutput: 'export'にしても、Next.js 16.4.3ではビルドエラーになりません。HTMLが/_next/imageを指したまま出力され、静的配信では画像が404になります。 - AVIFを元画像にするサイトは要注意です。next-image-export-optimizer 1.21.2でも、srcsetは
.AVIF、書き出されるのは.WEBPだけという不整合が再現しました。 - 画像がロゴやSVG程度なら
images.unoptimized、画像CDNがすでにあるならカスタムローダーで足ります。
output: “export” で next/image の最適化が止まる仕組み
静的エクスポートは、next build時にルートごとのHTMLを生成してoutディレクトリへ書き出す動作です。設定は next.config.js の1行です。
// next.config.js
module.exports = {
output: 'export',
}
Next.js公式ガイドStatic Exportsは、非対応機能に「Image Optimization with the default loader」を挙げています。理由はエラーページexport-image-apiにあり、既定ローダーはImage Optimization APIに依存し、そのAPIはエクスポートしたアプリでは使えない、Next.jsは画像をビルド時ではなくリクエスト時に最適化する、と説明されています。サーバを持たない静的出力とは原理的にかみ合いません。
では何も対策せずにビルドするとどうなるか。Next.js 16.4.3のApp Routerで、静的インポートした1600×1067のJPEGを素の<Image>に渡したところ、next buildは成功しました。出力されたHTMLのsrcは/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fphoto…jpg&w=3840&q=75です。outを静的ファイルサーバで配信すると、このURLは404、元画像の/_next/static/media/photo…jpgは200でした。ビルドが通るので、画像が出ないことにデプロイ後まで気づかない構造です。静的出力とサーバレンダリングの前提差はNext.jsのレンダリング方式|SSG・ISR・SSR・CSRの違いとApp Routerでの選び方で整理しています。
回避策は3つです。最適化をやめる(images.unoptimized)、外部の画像配信サービスに任せる(カスタムローダー)、ビルド時に変換済み画像を書き出す(本記事の2ライブラリ)。以降で2ライブラリを先に見て、最後にライブラリ不要のケースを扱います。
next-export-optimize-images 4.7.0 の導入手順とNext.js 16での制約
next.config.jsのラップとビルドコマンドの変更
このライブラリは既存コードへの手入れが少なく済みます。npm i -D next-export-optimize-imagesで入れ、next.config.js を専用の関数で包み、ビルドコマンドに1つ足し、画像コンポーネントのimport元を差し替えます。
// next.config.js
const withExportImages = require('next-export-optimize-images')
module.exports = withExportImages({
output: 'export',
})
{
"scripts": {
"build": "next build && next-export-optimize-images"
}
}
import Image from 'next-export-optimize-images/image'
画質やリモート画像の設定はプロジェクトルートのexport-images.config.jsに置きます。<Picture>でWebPと元形式を併配信でき、検証でも1枚の元画像から15サイズ×JPEG・WebPの30ファイルが生成されました。Next.js 16はimages.imageSizesの既定値から16を外したため、サイズ数が15になっています(Next.js 16のリリース告知)。
Next.js 16.4.3で静的インポート画像が404になる問題
npmの4.7.0(npmレジストリの記録で2025年8月31日公開。2026年10月26日時点の最新版)はpeerDependenciesがnext: 14.x || 15.xです。Next.js 16.4.3と一緒にnpm iすると、npm 11.17.0はERESOLVE unable to resolve dependency treeで止まりました。--legacy-peer-depsを付ければ入ります。
入れても既定のビルドでは正しく動きません。next build(Turbopack)のあとにCLIを実行すると「Successful optimization!」と表示され、public/imagesに置いた画像の変換ファイル30枚は出力されました。一方、import photo from './photo.jpg'で静的インポートした画像は、HTMLのsrcsetが/_next/static/chunks/images/_next/static/media/photo.0z6ld4ie2qxbf_828.jpgなどを指しているのに、そのディレクトリ自体がoutにありません。成功メッセージが出ているのに、静的インポート画像はすべて404になります。
原因はライブラリの実装にあります。4.7.0のdist/index.jsは、next.config.js のwebpack()コールバックの中でNext.jsのnext-image-loaderを自前のローダーに差し替え、静的インポート画像を変換対象に登録しています。Next.js 16はnext buildの既定バンドラをTurbopackにしており、Turbopackはこのコールバックを実行しません。同リポジトリのPR #1302「fix: add next 16 + turbopack compatibility」が同じ原因を報告していますが、2026年5月13日の投稿から2026年10月26日時点までマージされていません。Next.js 16系の変更点全体はNext.js 16.3とは?Turbopack永続キャッシュとInstant Navigationsなど新機能を実装者目線で解説にまとめています。
next build –webpackによる静的インポート画像の変換
Next.js 16はnext build --webpackでバンドラをwebpackへ戻せます。ビルドスクリプトを次のように変えると、静的インポート画像も15サイズ×2形式の30ファイルがout/_next/static/chunks/images/_next/static/media/に出力され、HTMLのsrcsetと一致しました。
{
"scripts": {
"build": "next build --webpack && next-export-optimize-images"
}
}
注意点が2つあります。ハッシュ付きのファイル名がバンドラで変わるため(検証ではTurbopackがphoto.0z6ld4ie2qxbf、webpackがphoto.ec62d427)、CDNのキャッシュ設定をファイル名に依存させている場合は切り替え時に確認してください。もう1つは、peerDependenciesの範囲外で動かしている点です。Next.jsを更新するたびに、変換画像が出ているかを利用側で確かめ直す必要があります。
next-image-export-optimizer 1.21.2 のセットアップと既知の不具合
next.config.jsのenvブロックとExportedImageへの差し替え
もう一方は、next.config.jsでloader: "custom"を宣言し、ビルド後にCLIで画像を変換する構成です。バンドラのフックを使わないため、Turbopackが既定になっても仕組みが崩れません。npmの最新版1.21.2はnpmレジストリの記録で2026年10月18日(UTC)公開、peerDependenciesはnext: ^14.2.18 || ^15.0.3 || ^16.0.0です。Next.js 16対応は1.20.1(2025年12月26日、リリースノートの項目は「Upgrade to Next 16」)で入りました。以下は検証に使った1.21.2の設定です。
// next.config.js
module.exports = {
output: "export",
images: {
loader: "custom",
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
transpilePackages: ["next-image-export-optimizer"],
env: {
nextImageExportOptimizer_imageFolderPath: "public/images",
nextImageExportOptimizer_exportFolderPath: "out",
nextImageExportOptimizer_quality: "75",
nextImageExportOptimizer_storePicturesInWEBP: "true",
nextImageExportOptimizer_generateAndUseBlurImages: "true",
},
};
インストールはnpm install next-image-export-optimizer、ビルドスクリプトはnext build && next-image-export-optimizerです。画像はExportedImageに差し替えます。デフォルトエクスポートなので、import名をImageにすればJSXの記述はそのまま使えます。
import ExportedImage from "next-image-export-optimizer";
<ExportedImage
src="images/photo.jpg"
alt="写真"
width={800}
height={533}
/>
この設定でNext.js 16.4.3を既定のTurbopackのままビルドすると、CLIは「Found 3 supported images」「resulting in 51 optimized images」と出力し、6.6秒で終わりました。51はCLIが表示した予定数で、実際に出力されたのは49ファイルです(public配下の2画像が各17枚、静的インポート画像が15枚)。17サイズはimagesのimageSizes・deviceSizesで指定した16個とblur用の10pxです。静的インポート画像(幅1600px)は、元の幅を超える2048と3840が作られず、1920までの15サイズがout/nextImageExportOptimizer/に出力され、HTMLのsrcsetと一致しました。前者で--webpackが必要だった静的インポートが、こちらは既定のビルドで通ります。
AVIF入力でsrcsetと出力ファイルがずれる不具合(1.21.2で再現)
Next.js 16に対応しているから安全、とは言えません。issue #263は、元画像がAVIFでstorePicturesInWEBPが有効(既定)のとき、srcsetは.AVIFのパスを出し、変換処理は.WEBPを書き出すため本番で404になる、と報告しています。修正を提案したPR #264は、GitHub APIの記録で2026年10月6日にマージされないままcloseされています。
1.21.2でphoto2.avifを渡して確かめると、HTMLのsrcsetは/images/nextImageExportOptimizer/photo2-opt-828.AVIFを指し、出力フォルダにはphoto2-opt-*.WEBPが17枚あるだけで.AVIFは0枚でした。報告どおりの不整合です。元素材にAVIFが混ざるサイトは、ビルド前にJPEGかPNGへ変換しておくのが確実です。
2つのライブラリの違いと選び方
対応バージョンと利用規模の比較
| 項目 | next-export-optimize-images | next-image-export-optimizer |
|---|---|---|
| npm最新版 | 4.7.0(2025-08-31) | 1.21.2(2026-10-18) |
| peer next | 14.x, 15.x | ^14.2.18 || ^15.0.3 || ^16.0.0 |
| Next 16.4.3でnpm i | ERESOLVE | 成功 |
| 既定ビルドの静的インポート | 404(未生成) | WebPを生成 |
| –webpackの静的インポート | JPEG・WebPを生成 | 不要 |
| 設定の置き場所 | export-images.config.js | next.config.jsのenv |
| 画像コンポーネント | Image, Picture, RemoteImage | ExportedImage |
| 出力形式 | 元形式+WebP | WebP(既定) |
| 週間ダウンロード | 1,708 | 13,740 |
| GitHub star | 474 | 541 |
| open issue | 12 | 11 |
週間ダウンロードはnpmのダウンロード統計で2026年10月16日〜22日の値、starとopen issue(PRを除く)は2026年10月26日のGitHub APIの値です。starやissueの数は拮抗していますが、ダウンロード数は約8倍の差があります。
どちらを選ぶかの判断基準
Next.js 16を使っている、または上げる予定があるなら next-image-export-optimizer です。peerDependenciesが16を含むことに加え、custom loaderとビルド後CLIという設計がバンドラの交代に影響されないことを、上の検証で確認できました。
リポジトリの更新日で選ぶと判断を誤ります。前者のリポジトリにはGitHub APIの記録で2026年5月12日にもpushがありますが、利用者がインストールするのはnpmに公開された版です。そこでは「Next.js 16のリリース(2025年10月21日)から1年経っても対応版が出ていない」ことが効きます。コミットの新しさではなく、公開済みの版のpeerDependenciesで判断してください。
Next.js 14系または15系に固定しているプロジェクトなら、next-export-optimize-images 4.7.0を選ぶ理由はあります。<Picture>による元形式とWebPの併配信や、リモート画像専用のコンポーネントが揃っているためです。ただしNext.js 16へ上げる際に4.7.0を使い続けるなら、webpackでの回避策を再検証するか、16対応のライブラリへの乗り換えを検討する必要があります。最初から next-image-export-optimizer で組むほうが手戻りは少なく済みます。Next.jsの各版の保守期限はNext.js 16の最新バージョンは16.4|リリース履歴・LTS期限・セキュリティ修正版と更新手順で確認できます。
ライブラリを入れない2つの選択肢
images.unoptimizedによる画像最適化の無効化
next.config.jsでimages: { unoptimized: true }を指定すると、画像はsrcのまま配信されます(Next.js 12.3.0以降)。サイズや形式の変換はされませんが、先に見た/_next/imageの404は起きません。
// next.config.js
module.exports = {
output: 'export',
images: {
unoptimized: true,
},
}
公式のImageコンポーネントのリファレンスは、1KB未満の小さい画像、SVGなどのベクター画像、GIFなどのアニメーション画像を最適化の恩恵がない例に挙げています。サイトの画像がロゴとアイコンだけなら、ライブラリを1本増やすより管理が楽です。
カスタムローダーによる画像CDNとの連携
ビルド時に画像を作らず、配信時の変換を外部サービスに任せる方法です。next.config.jsでloader: 'custom'とloaderFileを指定し、URLを組み立てる関数を書きます。公式ガイドはCloudinaryの例を載せています。以下はdemo環境用で、srcには/turtles.jpgのように先頭にスラッシュを付けたCloudinary上の画像パスを渡します。実運用ではdemoを自分のcloud nameに変更し、配信する画像を用意してください。
// next.config.js
module.exports = {
output: 'export',
images: {
loader: 'custom',
loaderFile: './my-loader.ts',
},
}
// my-loader.ts
export default function cloudinaryLoader({
src,
width,
quality,
}: {
src: string
width: number
quality?: number
}) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}${src}`
}
リポジトリに変換画像を持たずに済み、ビルド時間も伸びません。Amazon CloudFrontとは?仕組み・料金プランとエッジ機能・採用判断を実装者目線で解説のようなCDNを配信経路に置いているなら、画像変換の機能があるかを確かめてローダーを1本書くほうが構成は単純です。配信経路の設計はCDNとは?仕組み・キャッシュ制御からサービスの選び方まで実装目線で解説を参照してください。代わりに外部サービスへの依存と従量課金が生じ、画像が多いサイトほど費用が読みにくくなります。
よくある質問
next export コマンドは今も使えますか?
使えません。公式ガイドのVersion Historyによれば、next exportはv13.3.0で非推奨になり、v14.0.0で削除されて"output": "export"に置き換わりました。next.config.jsにoutput: 'export'を書けば、通常のnext buildがoutディレクトリを作ります。
output: “export” のまま next/image を使うとビルドエラーになりますか?
Next.js 16.4.3のApp Routerではエラーになりませんでした。ビルドは成功し、HTMLの画像URLが/_next/image?url=…のまま出力されるため、静的配信すると画像が404になります。images.unoptimized、カスタムローダー、本記事の2ライブラリのいずれかで対処してください。
next-export-optimize-images は Next.js 16 で使えますか?
2026年10月26日時点の4.7.0は公式には対応していません。npmではERESOLVEになり、--legacy-peer-depsで入れても既定のTurbopackビルドでは静的インポート画像が変換されません。使い続けるならnext build --webpackに変え、out配下に変換画像が出ているかをビルドごとに確認してください。
next build –webpack に戻すと何を失いますか?
失うのはTurbopackによる本番ビルドの高速化です。Next.js 16の告知は2〜5倍としていますが、これは告知上の値で、各プロジェクトで同じ倍率になるとは限りません。webpackへ戻した際の所要時間は、同じ条件で比較してください。--webpackを付けるのがnext buildだけなら、next devはTurbopackのままで、5〜10倍とされるFast Refreshの速さは開発時に残ります。
output: “export” では画像以外にどの機能が使えなくなりますか?
公式ガイドのUnsupported Featuresには、dynamicParams: trueの動的ルート、generateStaticParams()のない動的ルート、Requestに依存するRoute Handlers、Cookies、Rewrites、Redirects、Headers、Proxy、ISR、既定ローダーの画像最適化、Draft Mode、Server Actions、Intercepting Routesが並びます。サーバでの処理が要る機能のほか、ビルド時に出力するページを確定できない動的ルートや、Intercepting Routesのようなルーティング上の制約も含まれます。