Setting Up Automatic Bundle Size Check in CI/CD
Bundle grows unnoticed. A developer adds a dependency, a colleague imports a utility whole instead of needed function—and in a month JS bundle weighs 200 kB more than it should. Bundle size check in CI/CD stops this before it reaches production.
How It Works
Simple idea: on each PR or deploy we build the bundle, compare its size (and individual chunks) with baseline—values from previous deploy or fixed limits. If something exceeds the threshold—CI fails or leaves warning in PR.
Tools fall into two categories:
| Tool | Approach | When to Use |
|---|---|---|
bundlesize / bundlewatch |
Compare with fixed limits | Simple projects, quick setup |
size-limit (NEAR) |
Limits + import analysis | JS libraries, npm packages |
| Webpack Bundle Analyzer | Visualization, no CI blocking | Manual audit |
Vite rollup-plugin-visualizer |
Same for Vite | Manual audit |
| Relative CI / BuildBuddy | Compare PR vs base branch | Team projects, rich UI |
Setup via bundlewatch
Install:
npm install --save-dev bundlewatch
Config in package.json:
{
"bundlewatch": {
"files": [
{ "path": "dist/assets/index-*.js", "maxSize": "150kB" },
{ "path": "dist/assets/vendor-*.js", "maxSize": "400kB" },
{ "path": "dist/assets/*.css", "maxSize": "50kB" }
],
"ci": {
"trackBranches": ["main", "master"],
"repoBranchBase": "main"
}
}
}
In GitHub Actions:
name: Bundle Size Check
on: [pull_request]
jobs:
bundlewatch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- run: npx bundlewatch
env:
BUNDLEWATCH_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CI_REPO_OWNER: ${{ github.repository_owner }}
CI_REPO_NAME: ${{ github.event.repository.name }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_BRANCH: ${{ github.head_ref }}
CI_BRANCH_BASE: ${{ github.base_ref }}
bundlewatch leaves comment in PR with table: current size, delta, status.
Setup via size-limit
size-limit not only measures, but analyzes import tree—shows how much specific module weighs in isolation, accounting for tree-shaking and gzip.
npm install --save-dev size-limit @size-limit/preset-app
.size-limit.json:
[
{
"path": "dist/assets/index-*.js",
"limit": "150 kB",
"gzip": true
},
{
"name": "Vendor chunk",
"path": "dist/assets/vendor-*.js",
"limit": "380 kB",
"gzip": true
}
]
In package.json:
{
"scripts": {
"size": "size-limit",
"analyze": "size-limit --why"
}
}
--why runs webpack-bundle-analyzer and shows what drives the size.
Relative Limits Instead of Absolute
Absolute limits become outdated—project grows and constantly raising numbers gets tedious. Alternative: check delta relative to base branch.
Comparison script in CI:
#!/bin/bash
# Build current branch
npm run build
CURRENT_SIZE=$(du -sb dist/assets/*.js | awk '{sum += $1} END {print sum}')
# Save to artifact
echo $CURRENT_SIZE > /tmp/current_size.txt
# Load base branch size from CI artifacts
# (logic depends on CI system—example for GitHub Actions)
BASE_SIZE=$(cat /tmp/base_size.txt 2>/dev/null || echo $CURRENT_SIZE)
DELTA=$((CURRENT_SIZE - BASE_SIZE))
DELTA_PERCENT=$((DELTA * 100 / BASE_SIZE))
echo "Base: ${BASE_SIZE} bytes"
echo "Current: ${CURRENT_SIZE} bytes"
echo "Delta: ${DELTA} bytes (${DELTA_PERCENT}%)"
if [ $DELTA_PERCENT -gt 10 ]; then
echo "ERROR: Bundle grew by more than 10%"
exit 1
fi
Caching and Speed
Full rebuild on every PR is slow. Cache node_modules and Vite results:
- uses: actions/cache@v4
with:
path: |
node_modules
.vite
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
On typical project this cuts check time from 3–4 minutes to 40–60 seconds.
What to Check Besides Total Size
- Chunk count — growth in chunks with code splitting can increase HTTP requests
- Initial bundle size separately from lazy-loaded chunks — it affects LCP and TTI
- Duplicate dependencies — when one library is pulled into multiple chunks in different versions
For the latter: npm ls <package> or npx duplicate-package-checker-webpack-plugin.
Implementation Timeframe
Basic bundlewatch setup in existing CI pipeline — 4–8 hours: install, configure limits to current sizes, add step to workflow. size-limit setup with analysis and PR notifications — 1–2 business days including fine-tuning limits per chunk.







