How to Enable Build-Time Image Optimization with the `next-export-optimize-images` Next.js Plugin
The next-export-optimize-images plugin enables build-time image optimization by replacing Next.js's default image loader with a custom Webpack loader that records image variants during the production build, then processes those images using Sharp via a post-build CLI command.
The next-export-optimize-images package solves the challenge of optimizing images for static Next.js exports. This open-source plugin intercepts image processing during next build and generates pre-optimized static assets, allowing full use of Next.js Image components in statically exported sites without requiring a Node.js server runtime.
How the Plugin Architecture Works
The plugin operates through a two-phase build process that separates image detection from image processing.
During the build phase, the plugin swaps Next.js's default next-image-loader with its own next-export-optimize-images-loader via the withExportImages wrapper. As Webpack processes your application, this custom loader records every image size and format that Next.js would request and writes a manifest to .next/next-export-optimize-images-list.nd.json. According to the source code in src/loader/index.ts, this recording only occurs when isDev is false, ensuring zero overhead during development.
In the optimization phase, the CLI command next-export-optimize-images (exposed via bin/index.js) reads the generated manifest and runs Sharp to resize, convert, and compress images according to your configuration. The optimized files are placed in your static output directory, ready for deployment.
Key architectural components include:
withExportImages(src/withExportImages.ts): The configuration wrapper that validates settings, copiesexport-images.config.*into the package directory, and injects the custom Webpack loader.getConfig(src/utils/getConfig.ts): Safely loads and deserializes the optionalexport-images.config.js, including any function-based options likefilenameGenerator.- Image Components (
image.js/legacy/image.js): Re-exports of Next.js's Image component that resolve to the optimized static assets at runtime.
Installation and Configuration
Enable build-time image optimization by installing the package, wrapping your Next.js configuration, and extending your build script.
1. Install the Plugin
Add the package as a development dependency:
npm install -D next-export-optimize-images
2. Wrap Your Next.js Configuration
Import withExportImages in your next.config.js and wrap your existing configuration. The wrapper is asynchronous, so you must await it or return a Promise:
// next.config.js
const withExportImages = require('next-export-optimize-images')
module.exports = async () => {
return withExportImages({
output: 'export', // Required for static export
// ...other Next.js config
})
}
If you use additional plugins like @next/bundle-analyzer, compose them asynchronously:
const withExportImages = require('next-export-optimize-images')
const withAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' })
module.exports = async () => {
const config = await withExportImages({ output: 'export' })
return withAnalyzer(config)
}
3. Extend the Build Script
Modify your package.json scripts to run the optimizer after the standard Next.js build:
{
"scripts": {
"build": "next build && next-export-optimize-images"
}
}
The second command reads the manifest generated by the loader in src/loader/index.ts and creates the optimized image assets in your output directory.
Customizing Optimization Settings
Create an export-images.config.js (or .cjs) file in your project root to control output directories, quality settings, and format conversion. The withExportImages function copies this file into the package's node_modules directory so the loader can require it at build time.
// export-images.config.js
module.exports = {
outDir: 'out', // Static export output directory
imageDir: '_next/static/chunks/images', // Optimized image destination
quality: 80, // JPEG/WEBP quality (0-100)
convertFormat: [['png', 'webp']], // Convert PNG files to WEBP
generateFormats: ['webp', 'avif'], // Generate additional formats for <Picture>
remoteImages: async () => {
// Download and optimize external images before processing
return ['https://example.com/logo.png']
},
}
The convertFormat array accepts tuples of [sourceFormat, targetFormat] to transform images during optimization, while generateFormats creates modern format fallbacks for the Picture component.
Using the Optimized Image Component
Import the Image component from the package instead of next/image. The component behaves identically to Next.js's native implementation but resolves to the pre-optimized static files generated during the build process.
// pages/index.tsx
import Image from 'next-export-optimize-images/image'
export default function Home() {
return (
<>
{/* Local public image */}
<Image src="/images/hero.png" width={1920} height={1080} alt="Hero" />
{/* Imported image with hashed filename */}
import logo from '@/public/logo.png'
<Image src={logo} alt="Logo" />
{/* Remote image (downloaded at build time) */}
<Image src="https://example.com/remote.jpg" width={800} height={600} alt="Remote" />
</>
)
}
At runtime, these components resolve to paths like /_next/static/chunks/images/hero-1920.webp, serving the optimized assets directly from your CDN or static host.
Summary
withExportImageswraps yournext.config.jsto inject the custom Webpack loader during production builds.- The loader (
src/loader/index.ts) records image variants to.next/next-export-optimize-images-list.nd.jsonduring the build. - The CLI (
next-export-optimize-images) processes the manifest using Sharp to generate optimized static assets. export-images.config.jsprovides granular control over quality, format conversion, and remote image handling.- Import Image from
next-export-optimize-images/imageto serve the pre-optimized files in your application.
Frequently Asked Questions
How does the plugin handle remote images during build-time optimization?
The remoteImages configuration option in export-images.config.js accepts an async function that returns an array of URLs. The plugin downloads these images before the optimization phase begins, allowing external assets to be processed with the same Sharp pipeline as local files.
Can I use this plugin with other Next.js configuration wrappers?
Yes. Because withExportImages returns a Promise, you can compose it with other asynchronous plugins like @next/bundle-analyzer. Nest the calls by awaiting each wrapper sequentially, or use a composition utility to merge configurations.
What image formats does the build-time optimizer support?
The plugin supports all formats handled by Sharp, including JPEG, PNG, WEBP, AVIF, and GIF. Use convertFormat to transform source files into alternative formats (e.g., PNG to WEBP), and generateFormats to create multiple format variants for responsive image fallbacks.
Where are the optimized images stored after the build completes?
By default, optimized images are placed in _next/static/chunks/images within your output directory (configurable via the imageDir option in export-images.config.js). The manifest file at .next/next-export-optimize-images-list.nd.json tracks these locations during the build process.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →