Add a Performance Budget to CI
Set gzip size limits for entry bundles, fail pull requests that exceed them, and keep the budget visible as a review signal rather than a surprise outage.
Task
Prevent a pull request from silently shipping a significantly larger JavaScript bundle.
When to use this
A dependency or import change increases the main bundle by 30%, and nobody notices until users on slow networks report a regression.
Prerequisites
- A production build that outputs hashed assets
- A CI pipeline that runs on pull requests
- An agreed budget for the entry bundle and key routes
Steps
1. Install a size-checking tool and define budgets for the files that matter.
{
"size-limit": [
{ "path": "dist/_astro/*.js", "limit": "120 kB" },
{ "path": "dist/_astro/*.css", "limit": "40 kB" }
]
}
Expected output: The config fails when a matched asset exceeds its gzip budget.
2. Run the check after the production build in CI and upload the report as an artifact.
- run: pnpm build
- run: npx size-limit
- uses: actions/upload-artifact@<pinned-sha>
with:
name: size-limit-report
path: .size-limit/**/*.json
Expected output: A pull request that exceeds the budget fails the check.
3. Verify the gate by temporarily adding a large import in a branch and confirming the failure, then revert.
npx size-limitExpected output: The check passes on the baseline and fails on the oversized branch.
Troubleshooting
Problem
The budget fails on every small change
Solution
The limit is too tight for normal dependency updates. Measure the baseline and set a limit with a small reviewed margin.
Problem
The report is ignored
Solution
Add the size delta to the pull request summary and require a review for budget increases.
Limitations
- Bundle size is not runtime performance; it does not replace LCP or interaction measurements.
- Hashed filenames and multiple chunks make glob-based limits approximate; target stable entry chunks.
Make the regression visible
A performance budget turns a vague concern into a reviewable number. Set limits for the entry JavaScript and CSS, plus any route that dominates the user experience. The check runs after the production build, so it measures the artifact users download, not source files.
{ "path": "dist/_astro/*.js", "limit": "120 kB" }
Budgets need maintenance
A budget that is too strict blocks routine updates; one that is too loose never catches anything. Establish the current baseline, add a small margin, and require an explicit review when the budget changes. Track the trend over time instead of only pass/fail.
Pair with runtime metrics
Bundle size does not capture slow rendering, network variance, or third-party scripts. Combine the budget with Lighthouse or real-user metrics where available, and use the budget as an early warning rather than the only performance gate.
Verify the gate
Expected outcome: the baseline branch passes, and a branch that adds a known-large import fails with the measured size and budget in the output. Confirm by running the size check locally against the production build and by opening a temporary pull request that intentionally exceeds the limit. Remove the test change after verifying the failure.