Configure Webpack 5 Filesystem Cache and SplitChunks for Production Builds
Enable Webpack 5 filesystem caching and splitChunks for stable production asset names, while treating the cache as local build state.
26 Feb 2026, 11:26 UTC

The problem and the practical takeaway
As a production frontend application grows, Webpack builds slow down, and a small edit can change filenames across every emitted asset. When filenames change, browsers cannot reuse previously cached JavaScript, so users download more than necessary on repeat visits.
The practical takeaway: enable Webpack 5's persistent filesystem cache, declare the files that should invalidate it, split shared dependencies with splitChunks, and fingerprint assets with [contenthash]. Treat the cache directory as local, untrusted build state; do not deploy it or restore it from unverified sources.
Requirements
- Deterministic production builds: the same source and configuration should produce predictable asset names.
- Fast incremental rebuilds: unchanged modules should not be reprocessed.
- Cache invalidation: editing
webpack.config.js,package.json, or a lockfile must force affected modules to recompile. - Isolation: the build cache is a local artifact and must not be mixed with untrusted runtime data or shared writable locations.
- No secrets in bundles: environment variables and secrets must not live in source modules that Webpack emits.
Smallest suitable design
This design assumes Webpack 5. It enables the filesystem cache, configures long-term asset caching with content hashes, and splits vendor code into a separate chunk.
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
},
cache: {
type: 'filesystem',
buildDependencies: {
// webpack 5: declare files that invalidate the cache.
// Confirm the accepted shape for your installed webpack minor version.
config: [path.resolve(__dirname, 'webpack.config.js')],
},
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: -10,
reuseExistingChunk: true,
},
},
},
runtimeChunk: 'single',
},
};
[contenthash] is a hash of the module's contents. If a module's code does not change, its hash stays the same, so browsers can keep using the cached file. output.clean removes stale assets from dist before each build. runtimeChunk: 'single' extracts the Webpack runtime into its own file so it is not duplicated inside every shared chunk.
Add package.json and your lockfile (package-lock.json, yarn.lock, or pnpm-lock.yaml) to buildDependencies so dependency changes invalidate the cache. The exact buildDependencies schema varies between Webpack 5 releases; verify it against your installed version before merging this into CI.
Trust and data boundaries
The Webpack cache is a build-time local artifact, not a runtime trust boundary. Do not place it on a shared writable filesystem where another process could modify it. If you restore a cache from an external source, treat it as untrusted until its integrity is confirmed, because a poisoned cache could influence build output.
Never store secrets, API keys, or environment values in source modules or comments. Webpack may inline them into emitted assets. Use environment-specific configuration at runtime instead of baking values into the bundle.
Do not commit node_modules or node_modules/.cache/webpack to version control. The cache is local build state, not a deployment artifact.
Operational checks
Run these commands from <project-root> in a terminal as a normal user with write access to node_modules/.cache.
# First build: populates the cache
npx webpack --config webpack.config.js
# Second build with no source changes: should reuse the cache
npx webpack --config webpack.config.js --profile --json > build-stats.json
Expected check: the second build completes faster and emits identical asset names. Inspect build-stats.json for errors and warnings.
To verify invalidation, touch a tracked dependency and rebuild:
touch package.json
npx webpack --config webpack.config.js
Expected check: modules affected by the dependency change recompile. If nothing changes, buildDependencies may not cover the file you edited.
To inspect and reset the cache:
ls node_modules/.cache/webpack
rm -rf node_modules/.cache/webpack
Expected check: after deletion, a clean build still succeeds, though it takes longer because the cache is cold. Risk: deleting the cache forces a full rebuild on the next run, and concurrent builds sharing the same cache directory can corrupt it or exhaust disk space.
Use a bundle analyzer or Webpack stats JSON to confirm splitChunks produced the expected vendors chunk and did not duplicate runtime code across entry points.
Failure modes
- Stale cache: loader or plugin changes that are not listed in
buildDependenciesmay not invalidate the cache, producing outdated output. - Disk pressure: the filesystem cache can grow without bound. Schedule pruning or set retention to avoid filling build-agent disks.
- Corruption: concurrent builds, unclean shutdowns, or shared writable cache locations can corrupt cache data.
- Oversized shared chunks:
splitChunkswithchunks: 'all'can create large common chunks that delay page load, especially when many entry points share little code. - Hash collisions: rare, but
[contenthash]is not a cryptographic integrity guarantee for untrusted code.
Conditions that would change the design
- Ephemeral, read-only CI containers: disable the filesystem cache or use memory caching, because there is no persistent disk to benefit from it.
- Multiple applications sharing libraries: consider module federation instead of duplicating shared chunks in every build.
- HTTP/2 delivery: many small requests are acceptable, so large shared chunks can hurt granularity. Reconsider
splitChunksthresholds and cache group sizes.
Practical verification and limitations
Confirm the result by comparing two production builds with no source changes: asset names should be identical, and the second build should reuse the cache. Then edit a single module and confirm only that module's asset filename changes. [contenthash] detects content changes, but it is not a security control. The cache does not automatically track every loader or plugin internal change, so unrelated dependency updates can still produce stale results.
Reverting the change: remove the cache and optimization.splitChunks settings, delete dist and node_modules/.cache/webpack, and redeploy the previous configuration. This is necessary because the change alters emitted build artifacts.