How to Convert Images (PNG to WebP/AVIF) During Next.js Build

Use next-export-optimize-images to declare format conversions in export-images.config.js and the library automatically generates WebP and AVIF assets during the Next.js build process.

Converting PNG images to modern formats like WebP and AVIF during static site generation is essential for web performance. The next-export-optimize-images library handles this conversion automatically by integrating Sharp into the Next.js webpack pipeline. This guide explains how to configure the plugin to convert images from PNG to WebP and AVIF formats during build time.

Configure Format Conversion in export-images.config.js

The conversion behavior is controlled through an export-images.config.js file in your project root. According to the source code in [src/utils/getConfig.ts](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/getConfig.ts), the library reads the convertFormat and generateFormats options to determine output formats.

// export-images.config.js
module.exports = {
  /** Convert every PNG to WebP and AVIF */
  convertFormat: [
    // [sourceExtension, targetExtension]
    ['png', 'webp'],
    ['png', 'avif'],
  ],

  /** Always generate WebP & AVIF versions for all images */
  generateFormats: ['webp', 'avif'],

  /** Optional: quality (0-100) for the generated files */
  quality: 80,

  /** Optional: Sharp-specific options */
  sharpOptions: {
    webp: { quality: 80 },
    avif: { quality: 50 },
  },
};

Understanding convertFormat vs generateFormats

These two configuration options serve different purposes during the build:

  • convertFormat: Replaces the original file extension. When you specify ['png', 'webp'], the optimizer treats the image as a WebP file instead of PNG, effectively converting the primary format.
  • generateFormats: Creates additional copies in the specified formats while keeping the primary output. This is useful for providing fallback formats via the HTML <picture> element.

Integrate the Plugin with Next.js

After creating the configuration file, wrap your Next.js configuration with withExportImages in next.config.js. This function, defined in [src/withExportImages.ts](https://github.com/dc7290/next-export-optimize-images/blob/main/src/withExportImages.ts#L73-L104), injects a custom webpack loader required for the optimization pipeline.

// next.config.js
const withExportImages = require('next-export-optimize-images').default;

module.exports = withExportImages({
  images: {
    // Required: keep the custom loader
    loader: 'custom',
  },
});

For TypeScript projects using ES modules, use the .mjs extension:

// next.config.mjs
import withExportImages from 'next-export-optimize-images';

export default withExportImages({
  images: {
    loader: 'custom',
  },
});

How the Build Pipeline Processes Images

The conversion happens during the webpack phase of next build or next export through three core components:

1. Configuration Resolution

The getConfig function in [src/utils/getConfig.ts](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/getConfig.ts#L80-L94) validates and exposes your convertFormat settings to the build pipeline.

2. Output Path Generation

For each image processed, the buildOutputInfo function in [src/utils/buildOutputInfo.ts](https://github.com/dc7290/next-export-optimize-images/blob/main/src/utils/buildOutputInfo.ts) determines the final file extensions:

  • It checks if the source extension matches any entry in config.convertFormat (lines 50-60)
  • If matched, it replaces the extension variable with the target format (e.g., png becomes webp)
  • It then merges config.generateFormats with the primary extension to create an array of output formats
  • For each format, it generates the final output path and returns metadata including {output, src, extension, originalExtension}

3. Sharp Optimization Execution

The CLI optimizer in [src/cli/index.ts](https://github.com/dc7290/next-export-optimize-images/blob/main/src/cli/index.ts#L14-L25) walks the manifest of images and calls Sharp to write each format to disk:

// Simplified logic from src/cli/index.ts
case 'webp':
  await image.webp({ quality, ...sharpOptions }).toFile(outputPath);
  break;
case 'avif':
  await image.avif({ quality, ...sharpOptions }).toFile(outputPath);
  break;

A single source file like hero.png produces multiple optimized assets in the configured imageDir (default: _next/static/chunks/images):


_next/static/chunks/images/hero_800.webp
_next/static/chunks/images/hero_800.avif

Render Images with Automatic Format Selection

The library provides a Picture component in [src/components/client/picture.tsx](https://github.com/dc7290/next-export-optimize-images/blob/main/src/components/client/picture.tsx) that automatically renders a <picture> element with <source> tags for each generated format.

import { Picture } from 'next-export-optimize-images';

export default function Hero() {
  return (
    <Picture
      src="/hero.png"
      width={800}
      height={600}
      alt="Hero image"
      className="rounded"
    />
  );
}

This component reads the build manifest and outputs markup that allows browsers to select the best supported format:

<picture>
  <source srcset="_next/static/chunks/images/hero_800.avif" type="image/avif">
  <source srcset="_next/static/chunks/images/hero_800.webp" type="image/webp">
  <img src="_next/static/chunks/images/hero_800.png" alt="Hero image" width="800" height="600">
</picture>

Summary

  • Declare conversions in export-images.config.js using the convertFormat array to specify source-to-target mappings like PNG to WebP or AVIF.
  • Integrate the plugin via withExportImages in next.config.js with loader: 'custom' required.
  • Automated processing occurs during the build via buildOutputInfo (path logic) and optimizeImages (Sharp execution) in the CLI.
  • Multiple formats are supported simultaneously through generateFormats, creating additional copies beyond the primary conversion.
  • Client-side rendering uses the Picture component to automatically serve the optimal format based on browser support.

Frequently Asked Questions

What is the difference between convertFormat and generateFormats?

convertFormat replaces the original file format during the build (e.g., treating a PNG as a WebP file), while generateFormats creates additional copies in specified formats without replacing the primary output. Use convertFormat to migrate away from legacy formats, and generateFormats to provide modern fallbacks alongside originals.

Can I convert JPEG images to AVIF using this method?

Yes. Add ['jpg', 'avif'] or ['jpeg', 'avif'] to the convertFormat array in your export-images.config.js. The buildOutputInfo function in src/utils/buildOutputInfo.ts processes any extension pair defined in the configuration, not just PNG sources.

How do I adjust the quality settings for converted WebP and AVIF files?

Set the global quality option (0-100) in export-images.config.js for all formats, or specify granular options in sharpOptions. For example, set sharpOptions: { webp: { quality: 85 }, avif: { quality: 60 } } to control compression levels per format. These options are passed directly to Sharp in src/cli/index.ts.

Does this plugin work with the Next.js App Router?

Yes. The plugin works with both the Pages Router and App Router (Next.js 13+). When using TypeScript with the App Router, import withExportImages in next.config.mjs and ensure your export-images.config.js is in the project root. The Picture component is compatible with React Server Components when imported appropriately.

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 →