Size Limit: a performance budget for JavaScript bundles
Calculate the real cost to run your JS app or lib to keep good performance. Show error in pull request if the cost exceeds the limit.
At a glance
- What is it?
- Size Limit is a JavaScript performance budget tool that runs on CI and fails a commit when the real cost of a bundle exceeds a limit. It ships a CLI, three plugins and three presets, and it can measure time in a browser instead of bytes.
- Who is it for?
- Adopt Size Limit if you maintain a published npm library or an app bundle whose weight you want checked on every pull request, and if you can accept a size number that is a build artefact of a tool rather than a fact about your source. Do not adopt it if you need a stable, reproducible metric from a machine you do not control, because the time plugin's own documentation warns that measurements depend on available resources and might be unstable.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Size Limit measures, and for whom
Size Limit is a performance budget tool for JavaScript. The README states that it checks every commit on CI, calculates the real cost of your JS for end-users and throws an error if the cost exceeds the limit. That is the whole contract: a number, a threshold, and a non-zero exit that stops a pipeline.
The audience splits in two. Applications that have their own bundler and ship the bundle straight to a client (an email client, a CRM, a landing page, a blog with interactive elements) use the app preset. Small npm libraries with many small files and no bundler of their own use the webpack plugin, which creates an empty webpack project, adds the library and looks for the bundle size difference. The README lists MobX, Material-UI, Ant Design, Autoprefixer, PostCSS, Browserslist, EmojiMart, nanoid, React Focus Lock and Logux among users, and quotes reductions those projects made after the metric was in place, such as 25% for PostCSS and 33% for nanoid. Those are the projects' own commits, not measurements made by Size Limit's authors.
The tool is not a profiler and does not tell you what is slow at runtime. It tells you what a user must download and compile before your code runs. If your problem is a slow render loop rather than a heavy initial payload, this is the wrong instrument.
The CLI, three plugins and three presets
The mechanism is small enough to describe in full. A CLI tool finds plugins in package.json and loads the config. Plugins do the measuring. Presets bundle the common combinations so a user does not have to assemble them.
The plugin set is file, webpack and time. The file plugin measures files on disk, which is what an app that already ran its own bundler needs. The webpack plugin bundles your JS files into a single file so that dependencies and webpack polyfills are counted, which matters for a library that ships many small modules. The time plugin goes further: it compares the current machine performance with that of a low-priced Android device to calculate the CPU throttling rate, then runs headless Chrome (or desktop Chrome if available) to track the time a browser takes to compile and execute your JS.
The presets are app, big-lib and small-lib. Calculations include all dependencies and polyfills used in your JS, so a dependency you add in a pull request shows up in the number even if you never import it directly in a changed file.
The repository layout confirms the split: packages/ holds the individual packages, and the root package.json lists workspace dependencies on @size-limit/file, @size-limit/webpack, @size-limit/time, @size-limit/esbuild, @size-limit/rolldown and the -why and preset variants. The README describes three plugins and three presets, so the extra bundler packages are not covered by that description; treat the README as the stable surface and the package list as the current state of the monorepo.
Installing Size Limit for an app and setting a first limit
The README's app instructions install the tool plus the file plugin as dev dependencies. Run this in the project root:
npm install --save-dev size-limit @size-limit/fileThen add a size-limit section and a size script to package.json. The README shows the diff form; the resulting keys look like this:
"size-limit": [
{
"path": "dist/app-*.js"
}
],
"scripts": {
"build": "webpack ./webpack.config.js",
"size": "npm run build && size-limit"
}The size script builds first, because the file plugin measures what the build emitted. Running it prints a line in the form the README shows: Package size: 30.08 kB with all dependencies, minified and brotlied. Your number will differ; that figure is the README's example, not a benchmark.
Now add the limit. The README's advice is to add 25% to the current total size and use that as the limit:
"size-limit": [
{
"limit": "35 kB",
"path": "dist/app-*.js"
}
]Finally, wire it into the test suite so CI fails on regressions. The README appends npm run size to the existing test script rather than adding a separate step, which means the budget check runs wherever tests already run. If you have no CI service, the README points at GitHub Actions as a starting point. For a library rather than an app, the README directs you to a preset instead of the file plugin, and the install line changes accordingly.
Time-based limits and why the number moves
The README makes a fair argument for time over bytes: developers compare a JS bundle against an image, but a browser needs much more time to parse 100 kB of JS than 100 kB of an image, because JS compilers are complex. The time plugin exists to express the budget in the unit that actually affects a user.
The cost is stability. The README states plainly that these measurements depend on available resources and might be unstable, and links to an open issue about it. The plugin also derives a CPU throttling rate by comparing the current machine against a low-priced Android device, which means the same commit can produce different numbers on a loaded laptop and an idle CI runner. A time limit therefore needs more headroom than a byte limit, and a flaky failure is a real possibility on shared runners.
There is a second constraint: the time plugin needs Chrome. Headless Chrome is the default path, with desktop Chrome used if it is available. On a CI image without a browser, or in a container that cannot run one, the plugin has nothing to measure. Teams that cannot guarantee a browser should stay on the file or webpack plugin and treat time as a local diagnostic.
The time plugin is also configurable per check, with network speed and latency among the settings. That flexibility cuts both ways: a limit is only meaningful if the network profile behind it is written down and shared, otherwise two developers comparing failures are comparing different conditions.
Why a bundle is this big, and what --why adds
A failing budget tells you that you grew, not where. The README addresses this with --why, which it says can tell you why your library is of this size and show the real cost of all your internal dependencies. The analysis is done with Statoscope, a separate project by the same organisation, and the README shows a screenshot of its output.
This is the part of the tool that changes behaviour rather than just reporting. A number that goes up by 4 kB invites a shrug; a breakdown that names the dependency responsible invites a decision. The trade-off is that --why pulls in another tool and its own output format, and the README does not describe how to read that report or what it contains beyond the screenshot. If your team will not open the analysis, the flag adds a dependency for nothing.
Note also that the -why packages in the repository are split by bundler (@size-limit/esbuild-why, @size-limit/rolldown-why, @size-limit/webpack-why). The README's description of --why does not mention this split, so which bundler you use determines which package performs the analysis.
Where Size Limit is the wrong tool
Size Limit measures a build artefact, so it is only as honest as the build. If the path glob does not match what the bundler emits, the check passes on an empty or stale file and reports nothing useful. The README's example uses dist/app-*.js, which assumes a naming convention; a project that emits hashed chunks under a different directory will silently measure the wrong thing or nothing at all.
It is also a poor fit for code that does not ship to a browser. The README frames the whole tool around end-users downloading and executing JS. Server-side bundles, CLI tools and Node-only libraries gain nothing from a byte budget expressed in browser terms, and the time plugin's browser dependency makes it actively awkward there.
Third, a budget is a gate, not a diagnosis. It will block a pull request that adds 2 kB and say nothing about whether that 2 kB matters. Teams that adopt it without deciding in advance who is allowed to raise the limit end up with a number that gets bumped whenever it is inconvenient, which is worse than no budget because it looks like coverage.
Finally, the README is explicit that time measurements might be unstable. A pipeline that fails intermittently trains people to re-run rather than to investigate, and that habit spreads to other checks.
Alternatives and the difference in approach
The closest alternative named in the README is bundler-native analysis. Size Limit's webpack plugin works by creating an empty webpack project, adding your library and looking for the bundle size difference, which is a deliberately isolated measurement. A webpack stats file or a bundle analyser run against your real application configuration answers a different question: it reports what your actual build produced, including the code splitting, the externals and the loader configuration you really use. That is more faithful to production and harder to turn into a stable threshold, because the number moves whenever the application config moves.
A second alternative is to do nothing automated and rely on review. That is what most projects do, and the README's list of adopters is a list of projects that decided manual review was not enough. The difference is not capability but enforcement: a reviewer can be persuaded, a failing check cannot.
A third option is measuring at runtime with real user monitoring, which captures the devices and networks your users actually have. Size Limit measures on the build machine and, for time, simulates a low-priced Android device. Real user data is more representative and arrives after release, when the cost of fixing it is higher.
Size Limit's own position sits between these: cheaper than a full bundle analysis to keep green, more enforceable than review, and earlier than production telemetry.
Maintenance, licensing and upgrade cost
The repository is not archived, and its last push was on 2026-09-15. Releases 13.1.0 and 13.1.1 landed on 2026-09-12, and 14.0.0 on 2026-09-15, so the project is being released on a short cadence at the time of writing. A major version bump in that window is the thing to check before upgrading: read CHANGELOG.md at the repository root for what 14.0.0 changed, since the README does not describe version-specific migration.
The project is MIT licensed. That permits commercial use and modification, and it comes with no warranty. Nothing here is legal advice; if your organisation has rules about the licences of build-time dependencies, the MIT text in the LICENSE file at the repository root is what your process needs to read.
Upgrade cost is mostly the cost of plugin compatibility. The root package.json pins workspace versions of @size-limit/file, @size-limit/webpack, @size-limit/time and their preset and bundler variants together, which suggests the packages are released in lockstep. A project that installs size-limit and @size-limit/file separately should upgrade both at once rather than letting one drift. The repository is a pnpm workspace, so the published packages are built from packages/ and the root manifest is not the one consumers install. Budget a re-run of the size script after any upgrade to confirm the number has not shifted for reasons unrelated to your code.
Editorial conclusion
Adopt Size Limit if you maintain a published npm library or an app bundle whose weight you want checked on every pull request, and if you can accept a size number that is a build artefact of a tool rather than a fact about your source. Do not adopt it if you need a stable, reproducible metric from a machine you do not control, because the time plugin's own documentation warns that measurements depend on available resources and might be unstable. Before trusting a limit, run the size script once to see the current number, set the limit with headroom as the README suggests, and confirm the path glob matches the files your build actually emits.
Frequently asked questions
Is there a limit on the size in Size Limit?
Yes, and you set it yourself. The README advises adding 25% to the current total size and using that as the limit in package.json, after which Size Limit throws an error if the cost exceeds it.
What does file size limit mean in Size Limit?
It is the threshold you configure for a path glob, expressed in kB, and the tool fails the check when the measured cost goes above it. The README's app example uses a limit of 35 kB for dist/app-*.js.
How do I limit file size with Size Limit?
Add a size-limit section to package.json with a path and a limit, then add a size script that builds and runs size-limit. The README also suggests appending npm run size to the existing test script so the check runs on CI.
What is Size Limit in JavaScript?
It is a performance budget tool for JavaScript that checks every commit on CI, calculates the real cost of your JS for end-users and throws an error if the cost exceeds the limit. It ships a CLI, the file, webpack and time plugins, and the app, big-lib and small-lib presets.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ai-size-limit)