Back to the blog
Webpack· Jun 10, 2026· 6 min read

Webpack 5 asset modules: retiring file-loader, url-loader, and raw-loader

Webpack 5 built asset handling into core. Here's the asset/resource, asset/inline, and asset/source types, the parser.dataUrlCondition size threshold, and how to migrate off the old loaders.

#webpack#assets#migration#build-tools

Before Webpack 5, handling a non-JS asset - an image, a font, a raw text file - meant installing and configuring one of three community loaders: `file-loader` (emit as a separate file), `url-loader` (inline as a data URI below a size threshold), or `raw-loader` (import as a raw string). Webpack 5 absorbed all three into core as 'asset modules,' with no extra dependency required.

The four asset module types

module.exports = {
  module: {
    rules: [
      // Replaces file-loader: always emit a separate file
      { test: /\.png$/, type: 'asset/resource' },

      // Replaces url-loader: inline as base64 data URI, always
      { test: /\.svg$/, type: 'asset/inline' },

      // Replaces raw-loader: import file content as a string
      { test: /\.txt$/, type: 'asset/source' },

      // Replaces url-loader's size-threshold behavior:
      // small files inline, large files emit separately - automatically
      {
        test: /\.(png|jpe?g|gif)$/,
        type: 'asset',
        parser: { dataUrlCondition: { maxSize: 8 * 1024 } },
      },
    ],
  },
};

Plain `type: 'asset'` (no suffix) is the one that replaces `url-loader`'s most-used behavior: it picks resource or inline automatically based on `parser.dataUrlCondition.maxSize`. Small icons and sprites end up inlined as data URIs (saving an HTTP request), while large images emit as separate files (avoiding a bloated JS bundle) - all without a size-threshold decision you have to hand-tune per file type.

Controlling output filenames

module.exports = {
  output: {
    assetModuleFilename: 'assets/[hash][ext][query]',
  },
};

// Or per-rule, for finer control:
{
  test: /\.woff2?$/,
  type: 'asset/resource',
  generator: { filename: 'fonts/[hash][ext]' },
}

The migration checklist

  • Delete file-loader, url-loader, raw-loader from package.json entirely - none of them are needed alongside Webpack 5's built-in asset modules.
  • Replace `use: ['file-loader']` rules with `type: 'asset/resource'`.
  • Replace `use: [{ loader: 'url-loader', options: { limit: 8192 } }]` with `type: 'asset'` plus a matching `parser.dataUrlCondition.maxSize`.
  • Replace `use: ['raw-loader']` with `type: 'asset/source'`.
  • Double check any code relying on url-loader's specific data-URI MIME type behavior for non-standard extensions - asset modules infer MIME type from extension and can differ for obscure formats.
If your Webpack config still lists file-loader or url-loader as a dependency in 2026, that's a five-minute deletion, not a project - do it the next time you're in the config file for any other reason.

Written by Appesto Engineering.