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.
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.