# How the next-export-optimize-images CLI Performs Image Optimization

> Discover how the next-export-optimize-images CLI optimizes images through configuration loading, manifest building, and parallel processing with Sharp and smart caching for efficient image optimization.

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

---

**The next-export-optimize-images CLI orchestrates a multi-stage pipeline that loads Next.js configuration, builds a comprehensive manifest of local and remote images, and processes them in parallel using Sharp with intelligent caching to eliminate redundant work.**

The `next-export-optimize-images` library extends Next.js static exports with advanced image optimization capabilities. When you run the CLI command, the entry point at [`bin/index.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/bin/index.js) bootstraps a sophisticated pipeline that transforms and compresses your assets. Understanding how this CLI performs image optimization helps developers debug build issues and optimize CI/CD performance.

## CLI Entry Point and the run() Function

The journey begins in [`bin/index.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/bin/index.js), a thin wrapper that loads the compiled CLI module:

```javascript
#!/usr/bin/env node
require('../dist/cli').run({})

```

This invocation triggers the `run()` function defined in [`src/cli/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts) (lines 90‑100). This function serves as the orchestration layer, performing four critical initialization steps:

1. **Load user configuration** via `getConfig()` from [`src/utils/getConfig.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/getConfig.ts)
2. **Resolve the manifest path** 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)
3. **Load Next.js image configuration** using `loadConfig(PHASE_PRODUCTION_BUILD, cwd)` to obtain `deviceSizes` and `imageSizes`
4. **Execute optimization** by awaiting `optimizeImages()`

## Configuration Loading and Manifest Generation

The `optimizeImages` function (source: [`src/cli/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts), lines 70‑140) constructs a comprehensive inventory of every image requiring processing. This manifest generation handles three distinct asset sources:

- **Existing export manifest**: Parses and de-duplicates entries from previous builds using `processManifest()` and `uniqueItems()`
- **Remote images**: When `config.remoteImages` is defined, each URL expands into size-specific entries via `buildOutputInfo` from [`src/utils/buildOutputInfo.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/buildOutputInfo.ts)
- **Public folder assets**: Recursively scans the `public/` directory for PNG, JPG, WEBP, AVIF, and GIF files using `recursive-readdir`

Each manifest entry conforms to a strict TypeScript interface containing the output filename, source path, target width, desired extension, and optional external URL.

## Parallel Processing and Intelligent Caching

To maximize throughput, the CLI groups manifest items by source path into a `srcMap`. This ensures each source file undergoes **exactly one** `fs.readFile` operation regardless of how many sizes or formats derive from it.

The caching system, implemented in [`src/cli/utils/cache.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/utils/cache.ts), eliminates redundant processing:

- **Cache directory**: Creates `defaultCacheDir` to store previously optimized files
- **SHA-256 hashing**: Generates a hash of the original image buffer to serve as a cache key
- **Cache lookup**: Before invoking Sharp, the code checks for existing entries; cache hits trigger a direct file copy and increment `cacheMeasurement`
- **Cache persistence**: Writes updated manifest data via `writeCacheManifest`

Use the `--noCache` flag to bypass this behavior and force full re-optimization.

## Sharp Image Transformations in getOptimizeResult

The core optimization logic resides in `getOptimizeResult` (source: [`src/cli/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts), lines 44‑78). This function validates formats, manages file I/O, and executes the Sharp pipeline:

```typescript
const image = sharp(imageBuffer, { sequentialRead: true, animated: true })
image.rotate().resize({ width, withoutEnlargement: true })

```

### Supported Format Outputs

For each target extension validated by `formatValidate` (supporting `jpeg`, `jpg`, `png`, `webp`, and `avif`), the CLI applies format-specific Sharp methods:

- **JPEG/JPG**: `image.jpeg({ quality, ...sharpOptions?.jpg })`
- **PNG**: `image.png({ quality, ...sharpOptions?.png })`
- **WebP**: `image.webp({ quality, ...sharpOptions?.webp })`
- **AVIF**: `image.avif({ quality, ...sharpOptions?.avif })`

Each processed image writes to two locations simultaneously: the final destination path and the cache directory. Non-optimizable formats like SVG or GIF bypass transformation and copy directly to the output folder, with optional tracking in `invalidFormatAssets`.

## Progress Reporting and Build Summary

The CLI provides real-time feedback through [`src/cli/utils/cliProgressBar.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/utils/cliProgressBar.ts). The `cliProgressBarStart` function initializes a progress bar based on the manifest length, while `cliProgressBarIncrement` updates after every processed image—whether cached, optimized, or failed.

Upon completion, the CLI outputs a summary including cache hit ratios, error counts, and lists of non-optimized assets, concluding with a "Successful optimization!" message.

## Summary

- The [`bin/index.js`](https://github.com/dc7290/next-export-optimize-images/blob/main/bin/index.js) entry point delegates to `run()` in [`src/cli/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts), which coordinates the entire pipeline
- **Manifest generation** combines Next.js export data, remote images, and public folder scans into a unified processing queue
- **Intelligent caching** uses SHA-256 hashing to skip redundant Sharp operations, significantly accelerating rebuilds
- **Sharp transformations** handle JPEG, PNG, WebP, and AVIF outputs with configurable quality settings and respect for `withoutEnlargement` constraints
- The CLI reports progress via a terminal progress bar and provides detailed metrics on cache efficiency and errors

## Frequently Asked Questions

### What image formats does the next-export-optimize-images CLI support?

The CLI supports optimization of **JPEG**, **PNG**, **WebP**, and **AVIF** formats through the Sharp library. The `formatValidate` function in the source code explicitly checks for these extensions. **GIF** and **SVG** files are not processed by Sharp; instead, the CLI copies them directly to the output directory while optionally logging them as non-optimized assets.

### How does the caching mechanism work to speed up builds?

The CLI implements a file-based cache system in [`src/cli/utils/cache.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/utils/cache.ts). Before processing any image, it calculates a **SHA-256 hash** of the original file buffer. If a matching hash exists in the cache directory (`defaultCacheDir`), the CLI copies the cached file instead of running Sharp. This prevents redundant CPU-intensive encoding operations during incremental builds or when images remain unchanged between exports.

### Can the CLI optimize remote images fetched from external URLs?

Yes. When the configuration specifies `remoteImages`, the CLI expands each URL into multiple size-specific entries using `buildOutputInfo`. These entries include an `externalUrl` property in the manifest. During processing, the CLI downloads and optimizes these remote assets alongside local files, generatingstatically optimized versions in the export output.

### What happens if the CLI encounters an unsupported image format?

If `formatValidate` determines an extension is not optimizable (such as SVG or GIF), the CLI bypasses the Sharp pipeline entirely. It uses `fs.copy` to transfer the file unchanged to the destination directory. The system tracks these files in `invalidFormatAssets` and can report them in the final summary, ensuring developers are aware of which images did not undergo compression.