ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 78

  1. Blog

Clsx vs classnames: 294 B vs 857 B Gzip

Aditya Challa·5 October 2026·4 min read

Hands-on
On this page
  1. What I tested
  2. How wide was the size gap?
  3. How fast were the class builds?
  4. Which one should you pick?
  5. Sources
  6. Related

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)Minifiedgzip -9
clsx (browser)453 B294 B
classnames (browser)1,560 B857 B
clsx (neutral)453 B294 B
classnames (neutral)1,560 B857 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)clsxclassnames
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?

SituationMy pick
New React/Vue component libraryclsx
Bundle budget under about 400 B gzip for class helpersclsx
App already deep in classnames importsclassnames
You need the older classnames community snippets as-isclassnames
Migrating and cutting client JSclsx

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
clsxclassnamesjavascriptbundle sizeperformancereactvuefrontend

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.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 41

    ofetch vs ky: 4.1 KB vs 9.8 KB Gzip

    5 Oct 2026

  • Plate 35

    destr vs superjson: 665 B vs 4.1 KB Gzip

    5 Oct 2026

  • Plate 33

    ufo vs URL: 2.4 KB vs 0.5 KB Gzip

    5 Oct 2026

On this page

  1. What I tested
  2. How wide was the size gap?
  3. How fast were the class builds?
  4. Which one should you pick?
  5. Sources
  6. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove