Plate 78
Clsx vs classnames: 294 B vs 857 B Gzip
Aditya Challa4 min read
I bundled class helpers on this box: clsx 2.1.1 came in at 294 B gzip against classnames 2.5.1 at 857 B. On a 200,000-call class-build loop, clsx ran about 7.0M ops/s and classnames about 6.6M.
Short answer: pick clsx when you want the smallest className helper for React, Vue, or a design-system utility. Keep classnames if your codebase already imports it everywhere and a 563 B gzip save is not worth the churn. No affiliate links in this post.
What I tested
- Machine: 8 vCPU Intel Xeon / 15 GB RAM shared Linux cloud box, tested 6 Oct 2026 about 01:09–01:11 IST.
- Versions: clsx 2.1.1, classnames 2.5.1, Node 22.20.0, esbuild 0.28.2 minify + gzip -9.
- Fixture: /workspace/bench-clsx-classnames/. Size entries call the helper once with a string, object map, nested array, null, and undefined. Speed: the same argument list, 200,000 iters × 9 rounds (median) after warm; run twice.
- Findings: browser and neutral gzip both 294 B vs 857 B. Median speed run 1: 28.192 vs 30.380 ms (about 7.09M vs 6.58M ops/s); run 2: 28.493 vs 30.061 ms (about 7.02M vs 6.65M ops/s). Output strings matched. Disk trees about 9 KB vs 24 KB.
- One surprise: the speed gap was only about 5–8% on this fixture. The decision is almost entirely size, not throughput.
- Not tested: clsx/lite, TypeScript typings surface, CSS Modules composition, Tailwind class sorting, SSR hydration string equality beyond this fixture, or Rollup/webpack output.
How wide was the size gap?
| Build (esbuild minify) | Minified | gzip -9 |
|---|---|---|
| clsx (browser) | 453 B | 294 B |
| classnames (browser) | 1,560 B | 857 B |
| clsx (neutral) | 453 B | 294 B |
| classnames (neutral) | 1,560 B | 857 B |
clsx was about 2.9× smaller gzip on both platforms. Track shipped weight with size-limit vs bundlesize. After a swap, prune unused imports with knip vs depcheck.
How fast were the class builds?
| Path (200,000 calls, median of 9) | clsx | classnames |
|---|---|---|
| mixed string/object/array args (run 1) | 28.192 ms (7.09M/s) | 30.380 ms (6.58M/s) |
| mixed string/object/array args (run 2) | 28.493 ms (7.02M/s) | 30.061 ms (6.65M/s) |
On this box clsx was only a little faster. Utility-class merges sit next to my lightningcss vs PostCSS notes when the question is CSS pipeline weight, not className strings.
Which one should you pick?
| Situation | My pick |
|---|---|
| New React/Vue component library | clsx |
| Bundle budget under about 400 B gzip for class helpers | clsx |
| App already deep in classnames imports | classnames |
| You need the older classnames community snippets as-is | classnames |
| Migrating and cutting client JS | clsx |
Bottom line: clsx 2.1.1 shipped 294 B gzip against classnames 2.5.1 at 857 B, with class-build throughput about 7.0M vs 6.6M ops/s. Who should not switch: teams with hundreds of classnames imports and no size budget pressure — rewrite cost beats a 563 B gzip win. Lint the swap with Biome vs ESLint/Prettier. Test runner: Jest vs Vitest.
How this was made: I installed clsx and classnames on the ShopperCove box, measured esbuild minify+gzip sizes (browser and neutral), timed class-build loops twice, and recorded the JSON. The write-up was drafted with AI help and checked against that output.
Sources
- https://github.com/lukeed/clsx
- https://www.npmjs.com/package/clsx
- https://github.com/JedWatson/classnames
- https://www.npmjs.com/package/classnames
Related
- https://www.shoppercove.com/blog/size-limit-vs-bundlesize
- https://www.shoppercove.com/blog/knip-vs-depcheck
- https://www.shoppercove.com/blog/lightningcss-vs-postcss
- https://www.shoppercove.com/blog/unocss-vs-tailwind
- https://www.shoppercove.com/blog/biome-vs-eslint-prettier
- https://www.shoppercove.com/blog/jest-vs-vitest
- https://www.shoppercove.com/blog/picocolors-vs-chalk
- https://www.shoppercove.com/blog/dprint-vs-prettier
Lab evidence
What I found running this
Hands-on on ShopperCove box 6 Oct 2026 ~01:09-01:11 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). clsx 2.1.1 vs classnames 2.5.1, esbuild 0.28.2. Fixture /workspace/bench-clsx-classnames/: entries call helper with string, object map, nested array, null, undefined. Size: browser + neutral platforms, minify + gzip -9. Speed: 200,000 mixed-arg builds x 9 rounds (median) after warm, run twice. Medians: gzip 294 vs 857 B; run1 28.192 vs 30.380 ms (7.09M vs 6.58M ops/s); run2 28.493 vs 30.061 ms (7.02M vs 6.65M). Output strings matched. Disk ~9 KB vs ~24 KB. Raw: res-bundle.json, res-speed-run1.json, res-speed-run2.json. Not tested: clsx/lite, CSS Modules composition, Tailwind sorting, Rollup/webpack. No affiliate.