How to Define a Custom Filename Generator in next-export-optimize-images

Define a filenameGenerator function in your export-images.config.js that receives { path, name, width, extension } and returns a string to control exactly how optimized image files are named during static export.

The next-export-optimize-images library provides a custom filename generator hook that overrides the default image naming convention. This configuration option lives in your project root config file and gives you programmatic control over output paths, enabling cache-busting hashes, custom directory structures, and collision prevention when building static Next.js sites.

Where filenameGenerator is Implemented in the Source Code

The functionality spans three critical areas of the codebase: type definitions, runtime reconstruction, and build-time execution.

Type Definition and Config Loading

In src/utils/getConfig.ts (lines 58–66), the TypeScript interface defines the exact signature your function must match:

filenameGenerator?: (args: {
  path: string;
  name: string;
  width: number;
  extension: string;
}) => string;

When your configuration is processed, the library serializes your function to a string and writes it to node_modules/next-export-optimize-images/export-images.config.js. During the build, getConfig.ts (lines 48–55) reconstructs the function using the Function() constructor, allowing you to write executable logic in a JSON-serializable config file.

Execution During the Build Process

The actual invocation happens in src/utils/buildOutputInfo.ts (lines 71–75). If config.filenameGenerator exists, the library calls it with the parsed image metadata; otherwise, it falls back to the default template:

`${pathWithoutName}/${name}_${width}.${extension}`

How filenameGenerator Works Step-by-Step

  1. Create export-images.config.js at your project root and export an object containing your filenameGenerator function.
  2. withExportImages copies that configuration object into the package's node_modules directory, stringifying any functions for transport.
  3. getConfig reads the generated file and reconstructs your filenameGenerator using Function('return (...)') to restore executable code.
  4. During static export, buildOutputInfo receives each source image's src and target width, parsing the source into path, name, and extension components.
  5. If filenameGenerator is defined, the library invokes it with { path, name, width, extension } and uses the returned string as the final filename under config.imageDir.
  6. The resulting file is written to the export folder (e.g., out/_next/static/chunks/images/<your-filename>).

Why Use a Custom Filename Generator?

Implementing a custom generator solves specific deployment and caching challenges:

  • Namespace control – Organize images into sub-folders or flatten directory structures using custom separators.
  • Cache busting – Embed MD5 hashes, timestamps, or content-derived tokens to invalidate CDN caches when images change.
  • Collision avoidance – Prevent images with identical filenames from different source directories from overwriting each other (the default pattern only includes the file name and width).
  • Legacy compatibility – Match existing folder structures required by downstream CDNs or asset management systems.

filenameGenerator Configuration Examples

Flatten Paths with Hyphens

Replace directory slashes with hyphens to create a flat output structure:

// export-images.config.js
/**
 * @type {import('next-export-optimize-images').Config}
 */
module.exports = {
  filenameGenerator: ({ path, name, width, extension }) =>
    `${path.replace(/^\//, '').replace(/\//g, '-')}-${name}_${width}.${extension}`,
};

Result: /images/sample.png at width 1920 becomes images-sample_1920.png.

Add Content Hash for Cache Busting

Generate unique filenames based on source content to ensure browsers fetch fresh assets:

const crypto = require('crypto');

module.exports = {
  filenameGenerator: ({ path, name, width, extension }) => {
    const hash = crypto.createHash('md5')
      .update(`${path}/${name}.${extension}`)
      .digest('hex')
      .slice(0, 8);
    return `${path.replace(/^\//, '')}/${name}-${hash}-${width}.${extension}`;
  },
};

Result: /avatars/user.png becomes avatars/user-1a2b3c4d-300.png.

Preserve Directory Structure with Prefix

Maintain the original hierarchy while placing optimized files under a specific subdirectory:

module.exports = {
  filenameGenerator: ({ path, name, width, extension }) => {
    const base = path ? `${path}/${name}` : name;
    return `optimized/${base}_${width}.${extension}`;
  },
};

Result: /blog/2024/hero.png becomes optimized/blog/2024/hero_800.png.

TypeScript Configuration

For type-safe configuration in TypeScript projects:

// export-images.config.ts
import type { Config } from 'next-export-optimize-images';

const config: Config = {
  filenameGenerator: ({ path, name, width, extension }) => {
    return `${path.replace(/\//g, '_')}_${name}@${width}.${extension}`;
  },
};

export = config;

Note: When using TypeScript, compile the file to JavaScript before running Next.js, or rename it to export-images.config.cjs to ensure Node.js can require it.

Summary

  • Define filenameGenerator in export-images.config.js to override default image naming.
  • The function receives an object containing path, name, width, and extension, and must return a string.
  • The library reconstructs your function at runtime using Function() after serializing it to node_modules/next-export-optimize-images/export-images.config.js.
  • During the build, src/utils/buildOutputInfo.ts invokes your generator to determine the final output path under config.imageDir.
  • Use custom generators for cache busting, collision prevention, or matching legacy CDN folder structures.

Frequently Asked Questions

What parameters does the filenameGenerator function receive?

The function receives a single object with four properties: path (the directory portion of the source path), name (the filename without extension), width (the target optimization width in pixels), and extension (the file extension). It must return a string representing the desired output filename.

Where does the custom filenameGenerator place output files?

The returned filename is placed under the directory specified by config.imageDir, which defaults to out/_next/static/chunks/images/ within your Next.js export directory. Your returned string can include subdirectories (e.g., subfolder/image.png) to organize the output hierarchy.

Can I use TypeScript for my export-images.config.js file?

Yes, you can write export-images.config.ts and import the Config type from next-export-optimize-images for full type checking. However, you must compile the TypeScript to JavaScript before running the export, or use the .cjs extension and ensure your build pipeline handles the conversion.

What happens if I do not define a filenameGenerator?

If filenameGenerator is undefined, the library uses the default pattern implemented in src/utils/buildOutputInfo.ts: ${pathWithoutName}/${name}_${width}.${extension}. This places images in their original directory structure but appends the width to the filename, which may cause collisions if different source folders contain identical filenames.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →