# How the Caching Mechanism Prevents Repeated Image Optimization in next-export-optimize-images

> Learn how the caching mechanism in next-export-optimize-images prevents repeated image optimization by storing SHA-256 hashes and skipping redundant processing for faster builds.

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

---

**The caching mechanism prevents repeated image optimization by storing SHA-256 hashes of source images in a JSON manifest; when processing images, it compares the current file hash against stored values and skips the expensive Sharp pipeline entirely if they match.**

The `next-export-optimize-images` package accelerates static site builds by eliminating redundant image processing work. By persisting optimization results between runs, the tool ensures that unchanged images are copied from cache rather than re-processed through CPU-intensive Sharp operations.

## How the Cache Manifest Works

The caching system relies on a JSON manifest file that tracks previously optimized images. Located by default at [`node_modules/.cache/next-export-optimize-images/cached-images.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/node_modules/.cache/next-export-optimize-images/cached-images.json), this file stores an array of objects containing output paths and their corresponding source hashes.

When the CLI initializes, it invokes `readCacheManifest` from [`src/cli/utils/cache.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/utils/cache.ts) to load this data into memory:

```typescript
// src/cli/utils/cache.ts
export const readCacheManifest = (filePath = defaultCacheFilePath): CacheImages => {
  try {
    return JSON.parse(fs.readFileSync(filePath, 'utf-8'))
  } catch (_) {
    return []
  }
}

```

If the cache file does not exist—such as during the first run—the function returns an empty array, and the CLI proceeds to optimize all images normally.

## The SHA-256 Hash Comparison Logic

The core optimization prevention occurs in [`src/cli/index.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts) within the `getOptimizeResult` function. For each image processed, the system performs a cryptographic comparison to determine if the source file has changed since the last run.

First, the CLI computes a SHA-256 hash of the current image buffer:

```typescript
const hash = createHash('sha256').update(imageBuffer).digest('hex')

```

Next, it searches the in-memory `cacheImages` array for an entry matching the current output path. If found, it compares the stored hash against the newly computed value:

```typescript
if (currentCacheImage?.hash === hash) {
  await fs.copy(outputPath, filePath)
  cacheMeasurement()
  cliProgressBarIncrement()
  return
}

```

When the hashes match, the CLI bypasses the Sharp processing pipeline entirely, copying the previously optimized file directly from the cache directory to the final destination. This eliminates CPU-intensive operations for unchanged images.

## Cache Hit vs. Cache Miss Workflow

The distinction between cache hits and misses determines the processing path for each image.

**Cache Hit Workflow:**
1. Locate existing entry in [`cached-images.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/cached-images.json)
2. Compute SHA-256 hash of source image
3. Compare with stored hash
4. If equal, copy cached file to output directory
5. Skip Sharp optimization entirely

**Cache Miss Workflow:**
1. No matching entry found, or hash mismatch detected
2. Process image through Sharp with specified quality, format, and dimensions
3. Write optimized image to output directory
4. Update or create cache entry with new hash
5. Persist updated manifest to disk

When hashes differ—indicating the source image has been modified—the CLI updates the cache entry with the new hash value after processing:

```typescript
if (currentCacheImage !== undefined) {
  currentCacheImage.hash = hash
}

```

## Persisting Cache Between Runs

After processing all images, the CLI writes the updated manifest back to disk using `writeCacheManifest` from [`src/cli/utils/cache.ts`](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/utils/cache.ts):

```typescript
export const writeCacheManifest = (cacheImages: CacheImages, filePath = defaultCacheFilePath) => {
  fs.writeFileSync(filePath, JSON.stringify(cacheImages), 'utf-8')
}

```

This persistence ensures that subsequent builds benefit from previous optimization work. The cache directory defaults to `node_modules/.cache/next-export-optimize-images`, but this location can be configured through options.

## Disabling the Cache

For scenarios requiring fresh optimization—such as debugging or when the cache may be corrupted—the system provides a `--noCache` CLI flag. When invoked, this bypasses the cache lookup and write operations entirely:

```bash
npx next-export-optimize-images --noCache

```

Programmatically, the same behavior is achieved by setting `noCache: true` in the options object passed to `optimizeImages`:

```typescript
import { optimizeImages } from 'next-export-optimize-images/src/cli'

await optimizeImages({
  manifestJsonPath: './.next/next-export-optimize-images-list.nd.json',
  noCache: true,
  config: getConfig(),
  nextImageConfig: nextConfig.images,
})

```

## Summary

- The caching mechanism stores image metadata in [`cached-images.json`](https://github.com/dc7290/next-export-optimize-images/blob/main/cached-images.json) within `node_modules/.cache/next-export-optimize-images`
- SHA-256 hashes of source images