ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 38

  1. Blog

smol-toml vs @iarna/toml: 3x Faster on Deno Cargo

Aditya Challa·5 October 2026·5 min read

Hands-on
On this page
  1. What I tested
  2. Is smol-toml faster than @iarna/toml?
  3. How much smaller is the bundle?
  4. Do they parse the same way?
  5. Which one should you pick?
  6. Sources
  7. Related

I parsed Deno v2.1.4's real Cargo.toml (11,382 bytes, 34 workspace members) on this box: smol-toml 1.9.0 took about 0.16 ms per parse, while @iarna/toml 2.2.5 took about 0.47 ms. That is roughly 3× faster, for a 6.9 KB gzip browser bundle instead of 8.7 KB on Node.

Short answer: use smol-toml for new config loaders, Vite-style tooling and anything that might ship to the browser. Keep @iarna/toml only if you already depend on its familiar JSON-shaped API everywhere and do not need a clean browser build. 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:35 IST.
  • Versions: smol-toml 1.9.0 (published 22 Sep 2026), @iarna/toml 2.2.5 (last published Jul 2023), Node 22.20.0, esbuild 0.28.2 minify + gzip -9.
  • Inputs: Deno v2.1.4 Cargo.toml (11,382 B), Grafana ldap.toml (3,137 B), and a node-gyp pyproject.toml (2,936 B). Scripts and results are in /workspace/bench-smol-toml-iarna/.
  • Method: many ops per timed round (200–1,000), median of 9 rounds, two runs with the library order reversed.
  • Findings: Deno Cargo parse 0.159 / 0.153 ms (smol) vs 0.479 / 0.458 ms (iarna). Grafana ldap 0.018 vs 0.045 ms. pyproject 0.022 vs 0.072 ms. Stringify on the same objects was about 3× faster for smol too.
  • One surprise: @iarna/toml pulls Node's stream module, so a plain browser esbuild failed until I marked stream external. smol-toml bundled cleanly.
  • Not tested: browsers at runtime, Bun or Deno as hosts, TOML 1.1 extras, streaming parse, or untrusted / adversarial input.

Is smol-toml faster than @iarna/toml?

Input (median ms/op, 2 order-reversed runs)smol-toml 1.9.0@iarna/toml 2.2.5
Deno Cargo.toml, 11,382 B, parse0.159 / 0.1530.479 / 0.458
Grafana ldap.toml, 3,137 B, parse0.018 / 0.0180.045 / 0.045
node-gyp pyproject.toml, 2,936 B, parse0.022 / 0.0230.071 / 0.072
Deno Cargo.toml, stringify0.154 / 0.1450.483 / 0.476

Yes, about 3× on the Cargo.toml and the small configs. If you already compared YAML parsers for lockfiles, the same speed-vs-features trade shows up in yaml vs js-yaml.

How much smaller is the bundle?

Build (esbuild minify + gzip -9)Minifiedgzip
smol-toml parse+stringify (browser)17,303 B6,861 B
smol-toml parse only (browser)13,704 B5,578 B
@iarna/toml parse+stringify (Node platform)39,821 B8,746 B

smol wins on size and on browser packaging. @iarna/toml needs Node stream (or a polyfill) for a browser bundle. Track the delta in CI with size-limit vs bundlesize. Path helpers next to a TOML config loader are a separate choice; see pathe vs node:path.

Do they parse the same way?

Casesmol-toml@iarna/toml
Deno Cargo workspace.members length3434
Basic types, dotted keys, inline tables, array-of-tablesmatchmatch
Offset datetimeTomlDate (Date subclass)Date
Duplicate keysthrowsthrows
Comments after parse→stringifylost (0/2)lost (0/2)

Parsed values matched on every fixture I tried. The practical difference is the datetime class: both are instanceof Date and JSON.stringify to the same ISO string, but code that checks constructor.name will see TomlDate vs Date. Neither library keeps comments when you round-trip through a plain object. For schema checks on the parsed object, pair this with zod vs valibot or ajv vs zod.

Which one should you pick?

SituationMy pick
New Node or universal config loadersmol-toml
Browser or edge bundlesmol-toml
Existing @iarna/toml call sites, no browser needstay
Need comment-preserving editsneither (look for an AST/document API elsewhere)
Merging defaults into parsed configsee defu vs lodash.merge​

Bottom line: smol-toml was about 3× faster and easier to ship than @iarna/toml on this box, with matching parse results on real Cargo, Grafana and pyproject files. Who should not switch: teams pinned to @iarna/toml types across a large codebase with no size or browser pressure. Unused TOML deps after a migration belong in the same cleanup pass as knip vs depcheck.

How this was made: I installed both packages on the ShopperCove box, timed parse and stringify on three real fixtures in two order-reversed runs, measured esbuild bundle sizes (including the stream failure for @iarna/toml in the browser), and compared types, duplicates and comment round-trips. The JSON results sit next to the scripts. The write-up was drafted with AI help and checked against that output.

Sources

  • https://github.com/squirrelchat/smol-toml
  • https://github.com/iarna/iarna-toml
  • https://www.npmjs.com/package/smol-toml
  • https://www.npmjs.com/package/@iarna/toml
  • https://raw.githubusercontent.com/denoland/deno/v2.1.4/Cargo.toml

Related

  • https://www.shoppercove.com/blog/yaml-vs-js-yaml
  • https://www.shoppercove.com/blog/size-limit-vs-bundlesize
  • https://www.shoppercove.com/blog/pathe-vs-node-path
  • https://www.shoppercove.com/blog/defu-vs-lodash-merge
  • https://www.shoppercove.com/blog/zod-vs-valibot
  • https://www.shoppercove.com/blog/ajv-vs-zod
  • https://www.shoppercove.com/blog/knip-vs-depcheck
  • https://www.shoppercove.com/blog/lefthook-vs-husky
smol-tomliarna-tomltomljavascripttypescriptparsingperformancebundle size

Lab evidence

What I found running this

Hands-on on ShopperCove box 6 Oct 2026 ~01:35 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). smol-toml 1.9.0 vs @iarna/toml 2.2.5, esbuild 0.28.2 minify + gzip -9. Fixtures: Deno v2.1.4 Cargo.toml 11,382 B (raw.githubusercontent.com/denoland/deno/v2.1.4/Cargo.toml), Grafana ldap.toml 3,137 B, node-gyp pyproject.toml 2,936 B. Speed (multi-op rounds, 9-round median, order-reversed, ms/op): Cargo parse smol 0.15879 / 0.15303 vs iarna 0.47875 / 0.45763; ldap 0.01795 / 0.01781 vs 0.04531 / 0.04537; pyproject 0.02242 / 0.02255 vs 0.07105 / 0.0717; Cargo stringify 0.15377 / 0.14525 vs 0.48282 / 0.47566. Size: smol browser 17,303/6,861 B (parse-only 13,704/5,578); iarna Node 39,821/8,746 B; browser build fails without stream external. Behavior: both parse 34 workspace.members; TomlDate vs Date; duplicate keys throw; comment round-trip 0/2 both. Not tested: browsers runtime, Bun/Deno hosts, streaming, adversarial input. No affiliate.

Notes when a lab post goes up

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

Related links

  • Plate 18

    yaml vs js-yaml: 11x Faster Parse vs Kept Comments

    5 Oct 2026

  • Plate 09

    ohash vs object-hash: 10x Faster, 3.3 KB vs 11 KB

    5 Oct 2026

  • Plate 68

    Defu vs lodash.merge: 6x Faster, 452 B vs 4 KB

    5 Oct 2026

On this page

  1. What I tested
  2. Is smol-toml faster than @iarna/toml?
  3. How much smaller is the bundle?
  4. Do they parse the same way?
  5. Which one should you pick?
  6. Sources
  7. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove