Angular "ng build" Budget Exceeded - Fix bundle Size Errors in CI
Angular CLI enforces bundle-size budgets defined in angular.json. When the production build exceeds an error-level budget, ng build fails - by design, to stop bundle bloat from shipping. The fix is to shrink the bundle or, deliberately, raise the budget.
What this error means
ng build (production) fails with Error: bundle initial exceeded maximum budget. Budget 500.00 kB was not met by 120.00 kB with a total of 620.00 kB. It is deterministic and reproduces on every run until the bundle or budget changes.
✖ Error: bundle initial exceeded maximum budget.
Budget 500.00 kB was not met by 120.00 kB with a total of 620.00 kB.
✖ Failed to compile.Diagnose it: is it resolution, transform, or memory?
Bundler failures in CI fall into three families and the error text often points at the wrong one. A module that resolves on your machine and not on the runner is nearly always case sensitivity or a missing optional dependency; a transform error is a config or version mismatch; and an unexplained kill with no stack is the out-of-memory reaper, not a build error at all.
# 1. resolution: does the file exist with EXACTLY that case?
git ls-files | grep -i "the/imported/path"
# 2. transform: what versions is CI actually resolving?
npm ls webpack vite rollup esbuild typescript 2>/dev/null | head -20
# 3. memory: was it killed rather than failed?
# exit 137 = SIGKILL (OOM). Nothing in the bundler log will explain it.
node --max-old-space-size=4096 node_modules/.bin/vite buildCommon causes
Bundle grew past the error budget
A new dependency, an eagerly imported heavy library, or non-lazy routes pushed the initial bundle over the error threshold in angular.json budgets.
Budget set tighter than the app needs
The configured budget may be unrealistically low for the application, so a legitimate addition trips it.
How to fix it
Shrink the bundle (preferred)
- Lazy-load feature routes with
loadComponent/loadChildrenso they leave the initial bundle. - Import only what you use from large libraries; drop eager imports of heavy modules.
- Analyze the bundle (
ng build --stats-json+ a visualizer) to find the biggest contributors.
Adjust the budget deliberately
If the growth is justified, raise the threshold in angular.json rather than silencing the check.
// angular.json -> architect.build.options.budgets
{
"type": "initial",
"maximumWarning": "600kb",
"maximumError": "750kb"
}Make the build reproducible before you debug it
- Pin the Node major in
setup-nodeand inengines. A bundler that resolves native bindings will pick a different prebuilt binary across majors. - Delete
node_moduleslocally and reinstall from the lockfile before concluding the runner is at fault; most "works locally" reports are stale local state. - Set
CI=truelocally to reproduce. Several toolchains change behaviour under it, including treating warnings as errors. - Exit code 137 is an out-of-memory kill. Raise
--max-old-space-sizeor move to a larger runner rather than searching the bundler config.
How to prevent it
- Lazy-load routes so the initial bundle stays lean.
- Keep an
initialbudget with both warning and error thresholds. - Track bundle size in CI so regressions are visible before they fail the build.