ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 96

  1. Blog

es-toolkit vs lodash-es: 2.5 KB vs 9.6 KB Gzip

Aditya Challa·5 October 2026·5 min read

Hands-on
On this page
  1. What I tested
  2. How big was each bundle?
  3. Which helpers were faster?
  4. Which one should you pick?
  5. Sources
  6. Related

I bundled the same six helpers on this box: es-toolkit 1.52.0 came in at 2,469 B gzip against lodash-es 4.18.1 at 9,632 B. On a 100-row nested object, es-toolkit's cloneDeep ran about 2.7× faster than lodash-es.

Short answer: pick es-toolkit for new code that uses a handful of lodash-style helpers and ships to the browser. Stay on lodash-es when you rely on lodash-only options such as debounce maxWait, or when a codemod would touch hundreds of files. 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:04–01:06 IST.
  • Versions: es-toolkit 1.52.0, lodash-es 4.18.1, Node 22.20.0, esbuild 0.28.2 (browser platform, ESM, minify) + gzip -9.
  • Fixture: /workspace/bench-estoolkit-lodash/. The 6-helper entry imports debounce, groupBy, uniq, chunk, cloneDeep, and isEqual by name. Extra entries import debounce alone, and cloneDeep plus isEqual.
  • Speed: 10,000-row arrays for groupBy, uniq, and chunk; a nested object with 100 rows for cloneDeep and isEqual. Median of 9 rounds after warm-up, run twice. Both libraries returned identical results on all four parity checks.
  • Findings: 6-helper bundle 2,469 B vs 9,632 B gzip. debounce alone 337 B vs 1,449 B. cloneDeep 108 ms vs 291 ms per 2,000 clones; chunk 11.6 ms vs 26.3 ms per 2,000 calls.
  • One surprise: es-toolkit is the smaller bundle but the bigger install. node_modules/es-toolkit was about 18 MB on disk against about 2.6 MB for lodash-es, because it ships CJS, ESM, compat, and type builds.
  • Not tested: the es-toolkit/compat layer, lodash (CJS) with babel-plugin-lodash, throttle, get/set paths, TypeScript type checking speed, older browsers, or Rollup and webpack tree-shaking.

How big was each bundle?

Entry (esbuild browser, minify)Minifiedgzip -9
es-toolkit, 6 helpers6,826 B2,469 B
lodash-es, 6 helpers25,691 B9,632 B
es-toolkit, debounce only542 B337 B
lodash-es, debounce only2,914 B1,449 B

es-toolkit was about 3.9× smaller gzip for the six helpers and about 4.3× smaller for debounce alone. Most of the lodash-es weight came from cloneDeep and isEqual: an entry with just those two was 6,622 B gzip in lodash-es against 1,939 B in es-toolkit. Put a ceiling on it with size-limit vs bundlesize. Minifier choice is a separate, smaller lever; I compared those in Terser vs esbuild vs SWC minify.

Which helpers were faster?

Helper (median of 9)Callses-toolkitlodash-eslodash ÷ es-toolkit
cloneDeep, 100-row object2,000108.0 ms290.7 ms2.69×
chunk, 10k items by 1002,00011.6 ms26.3 ms2.27×
isEqual, 100-row object2,000160.7 ms192.2 ms1.20×
uniq, 10k numbers50094.3 ms99.1 ms1.05×
groupBy, 10k rows20038.2 ms40.3 ms1.06×

cloneDeep and chunk were clear wins, and the second run matched (2.72× and 2.24×). isEqual, uniq, and groupBy were close to a tie: on run two, isEqual was 1.06× and groupBy flipped to lodash-es at 0.97×. If you clone state often, compare this with structural sharing in Immer vs Mutative.

Which one should you pick?

SituationMy pick
New browser app using 5–10 helperses-toolkit
Hot path that deep-clones objectses-toolkit
You need debounce maxWait or lodash path stringslodash-es
Large codebase with hundreds of lodash importslodash-es now, es-toolkit/compat later
Node-only script where bundle size does not mattereither

Bottom line: es-toolkit 1.52.0 shipped 2.5 KB gzip against lodash-es 4.18.1 at 9.6 KB for six common helpers, and cloned a nested object about 2.7× faster. Who should not switch: teams whose code depends on lodash edge behavior. es-toolkit's debounce takes signal and edges options, not maxWait. Swap one helper at a time, check the build output with Rolldown vs Rollup, and remove lodash-es once knip vs depcheck reports it unused.

How this was made: I installed es-toolkit and lodash-es on the ShopperCove box, measured esbuild minify + gzip sizes for two entries, timed five helpers twice with parity checks, and saved the JSON (res-bundle.json, res-bundle-clone-eq.json, res-speed-run1.json, res-speed-run2.json). The write-up was drafted with AI help and checked against that output.

Sources

  • https://github.com/toss/es-toolkit
  • https://www.npmjs.com/package/es-toolkit
  • https://es-toolkit.dev/
  • https://github.com/lodash/lodash
  • https://www.npmjs.com/package/lodash-es

Related

  • https://www.shoppercove.com/blog/size-limit-vs-bundlesize
  • https://www.shoppercove.com/blog/terser-vs-esbuild-swc-minify
  • https://www.shoppercove.com/blog/immer-vs-mutative
  • https://www.shoppercove.com/blog/rolldown-vs-rollup
  • https://www.shoppercove.com/blog/knip-vs-depcheck
  • https://www.shoppercove.com/blog/source-map-explorer-vs-webpack-bundle-analyzer
  • https://www.shoppercove.com/blog/zod-vs-valibot
  • https://www.shoppercove.com/blog/zustand-vs-redux-toolkit
es-toolkitlodash-esbundle sizejavascript performanceclonedeeptree-shakinggzip

Lab evidence

What I found running this

Hands-on on ShopperCove box 6 Oct 2026 ~01:04-01:06 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). es-toolkit 1.52.0 vs lodash-es 4.18.1, esbuild 0.28.2 browser ESM minify + gzip -9. Fixture /workspace/bench-estoolkit-lodash/: named imports debounce, groupBy, uniq, chunk, cloneDeep, isEqual; extra debounce-only and cloneDeep+isEqual entries. Speed: 10k-row arrays (groupBy x200, uniq x500, chunk x2000), 100-row nested object (cloneDeep/isEqual x2000), median of 9 after warm, run twice. Run 1: gzip 2,469 vs 9,632 B; debounce 337 vs 1,449 B; cloneDeep 107.952 vs 290.740 ms; chunk 11.558 vs 26.259 ms; isEqual 160.737 vs 192.233 ms; uniq 94.268 vs 99.063 ms; groupBy 38.221 vs 40.339 ms (run 2 flipped to 0.97x). Parity 4/4. Disk ~18 MB vs ~2.6 MB. es-toolkit debounce has signal/edges, no maxWait; core has no get(). Raw: res-bundle.json, res-bundle-clone-eq.json, res-speed-run1.json, res-speed-run2.json. Not tested: es-toolkit/compat, babel-plugin-lodash, throttle, 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 80

    size-limit vs bundlesize: Should You Switch? 761ms vs 604ms

    size-limit 11.2.0 (@size-limit/file) vs bundlesize 1.0.0-beta.2 on 3 prebuilt dist JS files: brotli median 761 ms vs gzip 604 ms; size-limit gzip mode 621 ms. App reported 57.69 kB brotli / 62.20 kB gzip / 60.74 kB bundlesize gzip.

    5 Oct 2026

  • Plate 35

    cookie-es vs cookie: 2.3 KB vs 1.4 KB Gzip

    5 Oct 2026

  • Plate 81

    scule vs change-case: 570 B vs 795 B Gzip

    5 Oct 2026

On this page

  1. What I tested
  2. How big was each bundle?
  3. Which helpers were faster?
  4. Which one should you pick?
  5. Sources
  6. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove