# How next-export-optimize-images Works with Next.js Static Export

> Learn how next-export-optimize-images enhances Next.js static export. This plugin optimizes images during build using webpack and Sharp for responsive variants.

- Repository: [d-suke/next-export-optimize-images](https://github.com/dc7290/next-export-optimize-images)
- Tags: deep-dive
- Published: 2026-02-28

---

**The next-export-optimize-images plugin extends Next.js static export by injecting a custom webpack loader that collects image metadata during the build into a manifest file, then executes a post-build CLI process using Sharp to generate optimized, responsive image variants before deployment.**

The `dc7290/next-export-optimize-images` repository solves the limitation that standard Next.js image optimization requires a running Node.js server. By hooking into the static export pipeline, this plugin generates all optimized assets ahead of time, enabling fully static deployments on CDN or edge hosting without sacrificing image performance.

## Hooking into the Next.js Configuration

The plugin entry point is the **`withExportImages`** function exported from [`src/withExportImages.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/withExportImages.ts). This wrapper modifies the Next.js configuration to intercept image processing during the build.

### Configuration Validation and Setup

The plugin first validates that `images.unoptimized` is not enabled in [`next.config.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/next.config.js) (`src/withExportImages.ts:15-19`). It then loads the user-provided configuration from `export-images.config.{js,cjs}` and writes it into [`node_modules/next-export-optimize-images/export-images.config.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/node_modules/next-export-optimize-images/export-images.config.js) so the loader and CLI can `require` it later (`lines 32-58`).

### Webpack Loader Injection

The core mechanism replaces the default `next-image-loader` with a chain that runs the plugin's custom loader first, then the original Next.js loader (`src/withExportImages.ts:73-96`). An alias is added so Webpack can resolve the plugin's loader (`lines 98-100`).

## Build-Time Image Collection

During production builds, the custom webpack loader ([`src/loader/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/loader/index.ts)) intercepts every image import processed by Next.js.

### The Custom Webpack Loader

The loader receives the JSON metadata (`staticImageData`) that Next.js emits for each image and extracts the original `src` path (`src/loader/index.ts:28-30`). Using the **`buildOutputInfo`** utility ([`src/utils/buildOutputInfo.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/buildOutputInfo.ts)), it calculates every output variant including different widths, formats, and custom filenames (`src/loader/index.ts:38-45`).

### Manifest Generation

For each image variant, the loader appends a line to a newline-delimited JSON manifest located at [`.next/next-export-optimize-images-list.nd.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/.next/next-export-optimize-images-list.nd.json) (`src/loader/index.ts:47-50`). This manifest serves as the source of truth for the optimization CLI.

## CLI Optimization Pipeline

After `next build` completes, the user runs `next-export-optimize-images` to execute the post-build optimization. The CLI entry point is [`src/cli/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts).

### Manifest Processing

The CLI reads the manifest file (`src/cli/index.ts:74-77`) and expands the list with **remote images** (if configured) and **public-folder images** (`lines 84-138`). For each entry, `buildOutputInfo` is called again to compute exact output paths and formats (`lines 102-110`).

### Remote Image Handling

External images configured via `remoteImages` are downloaded once into the configured `externalImageDir` ([`src/cli/external-images/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/external-images/index.ts)). The CLI ensures these assets are processed alongside local images.

### Sharp-Based Optimization

The plugin uses **Sharp** to perform the heavy lifting. Each image buffer is resized to every required width, optionally converted to formats like WebP or AVIF, and written to both the cache and final output directory (`src/cli/index.ts:91-126`). A cache directory at `node_modules/.cache/next-export-optimize-images` skips re-optimizing unchanged files (`lines 70-89`).

## Runtime Component Support

For remote images rendered at request time, the plugin provides specialized components. When using `<RemotePicture/>` or `<RemoteImage/>`, the components write entries to the same manifest **at runtime** (production only), ensuring external assets are captured for the CLI step. See the generation loop in [`src/components/server/remote-picture.tsx`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/components/server/remote-picture.tsx) (`lines 24-58`).

## Configuration System

The plugin reads its configuration via [`src/utils/getConfig.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/getConfig.ts). This utility loads the user-provided config that was copied into `node_modules` during `withExportImages` execution, evaluates any stringified functions (such as `filenameGenerator`), and returns a fully typed `Config` object (`lines 37-55`).

## Implementation Examples

Integrate the plugin in [`next.config.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/next.config.js):

```javascript
const withExportImages = require('next-export-optimize-images')

module.exports = withExportImages({
  output: 'export',
  // Additional Next.js config
})

```

Add the post-build script to [`package.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/package.json):

```json
{
  "scripts": {
    "build": "next build && next-export-optimize-images"
  }
}

```

Configure optimization settings in [`export-images.config.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/export-images.config.js):

```javascript
module.exports = {
  imageDir: '_next/static/optimized',
  filenameGenerator: ({ path, name, width, extension }) =>
    `${path}/${name}-${width}.${extension}`,
  quality: 80,
  generateFormats: ['webp', 'avif'],
}

```

Use the optimized Image component:

```tsx
import Image from 'next-export-optimize-images/image'

export default function Home() {
  return (
    <Image
      src="/photos/hero.jpg"
      width={1920}
      height={1080}
      alt="Hero"
    />
  )
}

```

For external images:

```tsx
import RemotePicture from 'next-export-optimize-images/remote-picture'

export default function Avatar() {
  return (
    <RemotePicture
      src="https://example.com/avatar.png"
      width={200}
      height={200}
      alt="User avatar"
    />
  )
}

```

## Summary

- The **`withExportImages`** function wraps Next.js config to inject a custom webpack loader and validate settings
- The custom loader writes image metadata to [`.next/next-export-optimize-images-list.nd.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/.next/next-export-optimize-images-list.nd.json) during the build
- The post-build CLI processes the manifest using **Sharp** to generate responsive variants and alternative formats
- Remote images are supported through runtime manifest entries in [`src/components/server/remote-picture.tsx`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/components/server/remote-picture.tsx)
- Optimized images are cached in `node_modules/.cache/next-export-optimize-images` and output to `/_next/static/chunks/images` (or a custom `imageDir`)

## Frequently Asked Questions

### How does next-export-optimize-images differ from Next.js built-in image optimization?

Next.js built-in optimization requires a Node.js server to dynamically serve optimized images based on request parameters. next-export-optimize-images performs all optimization during the build phase, generating static files suitable for deployment to static hosting or CDNs without a running server.

### Where does the plugin store the list of images to optimize?

During the build, the custom webpack loader writes entries to [`.next/next-export-optimize-images-list.nd.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/.next/next-export-optimize-images-list.nd.json) using newline-delimited JSON format. The CLI reads this manifest to determine which images require processing, including both local and remote assets.

### Can next-export-optimize-images handle external remote images?

Yes. The plugin provides `<RemotePicture/>` and `<RemoteImage/>` components that write remote URLs to the manifest during server rendering. The CLI then downloads these to the configured `externalImageDir` and processes them alongside local assets using the same Sharp pipeline.

### What image processing library does the plugin use?

The plugin uses **Sharp** to resize images to multiple widths, convert between formats like WebP and AVIF, and control quality settings. Processed images are cached in `node_modules/.cache/next-export-optimize-images` to avoid redundant processing in subsequent builds.