Cache Vendor Code with Rollup's manualChunks for Stable Long‑Term Builds
Learn how Rollup's manualChunks option separates vendor code into a stable chunk, improving long‑term caching and reducing unnecessary downloads.
01 Apr 2026, 07:36 UTC

Introduction
When a web application bundles third‑party libraries together with its own source, a tiny edit in the app forces the browser to download the entire vendor bundle again. This wastes bandwidth and prevents effective long‑term caching. Rollup’s manualChunks option lets you split static dependencies into a separate chunk that only changes when the dependencies themselves change.
How manualChunks Works
Rollup builds a chunk for each distinct string returned by the manualChunks function. The function receives the resolved module ID and must return either a chunk name (string) or null/undefined to let Rollup use its default behavior. By returning a constant name for every ID that contains node_modules, all third‑party modules are grouped into one vendor chunk.
Worked Example
Assume a project with the following structure:
src/
main.js
package.json
rollup.config.js
src/main.js imports a few libraries from node_modules and contains application logic:
// src/main.js
import { debounce } from 'lodash-es';
import { render } from './utils.js';
function init() {
const data = fetchData();
render(debounce(data, 300));
}
init();
The Rollup configuration isolates vendor code:
// rollup.config.js
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
manualChunks: id => id.includes('node_modules') ? 'vendor' : undefined,
},
plugins: [terser()],
};
Running the build:
# Ensure you have Rollup ≥1.0 installed locally or globally
npx rollup -c
The dist folder now contains two files:
main.js– application‑specific codevendor.js– all lodash‑es and any othernode_modulesimports
If you edit only src/main.js and rebuild, the hash of vendor.js stays identical, proving the vendor chunk is stable. Adding a new dependency (e.g., npm i date-fns) and rebuilding changes the vendor hash, showing the chunk correctly reflects dependency updates.
Trade‑offs and Limitations
While a single vendor chunk improves caching, over‑splitting (e.g., one chunk per library) can increase the number of HTTP requests and complicate cache invalidation. Start with the simple node_modules → vendor split, measure the impact with tools like source‑map‑explorer, and only add further splits if a specific library is large and changes infrequently.
Note that manualChunks only affects static ES‑module imports. Dynamic imports (import()) are always treated as separate chunks, so mixing the two patterns may produce additional chunks you did not expect.
Actionable Closing
- Add the
manualChunksfunction shown above to yourrollup.config.js. - Run
npx rollup -cand verify thatdist/vendor.jsappears. - Make a change only to your application source, rebuild, and compare the
vendor.jshash (e.g., withshasum dist/vendor.js) before and after; it should remain unchanged. - Update a dependency, rebuild, and confirm the vendor hash changes.
- If you notice many small vendor chunks, consider consolidating them or keeping the single vendor chunk unless performance data justifies further splitting.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.