Skip to content

Backends and performance ​

Choose a backend using measurements of your dictionary, input and output volume.

Performance in charts ​

Measured snapshots, not a live benchmark or a claim about the latest npm release. Lower time and memory are better. Expand the tables for values and variation.

Scanning before and after optimization

All 18 scenarios share the same baseline. The dashed line is the original time (1×); a bar at 0.4× takes 40% of that time. Switch operations to see where the gains apply.

After / before · lower is faster · baseline = 1×

Exact measurements and variation
ScenarioBefore · msAfter · msAfter / beforeTime change
Tiny ASCII0.001269675 (0.000014722; 0.000023004)0.000136628 (0.00000104; 0.00000094)0.107609-89.24%
CRLF2.572690125 (0.057604125; 0.026924375)1.281498688 (0.02346875; 0.014897125)0.498116-50.19%
ASCII + combining2.80034375 (0.043317625; 0.037565125)2.659710937 (0.04278125; 0.04969275)0.94978-5.02%
Unicode at start2.463591125 (0.030835938; 0.006440125)2.329559937 (0.01759375; 0.027726625)0.945595-5.44%
ASCII prefix2.87225525 (0.0160625; 0.068546938)0.856292328 (0.007295562; 0.035654953)0.298125-70.19%
Early Unicode4.819791625 (0.036427125; 0.114406125)1.504946594 (0.014993531; 0.094178344)0.312243-68.78%
Ordinary text2.021273437 (0.0326745; 0.0097005)0.609461578 (0.006155594; 0.002634109)0.301524-69.85%
No matches2.472632813 (0.011533937; 0.012984375)0.718931641 (0.013856766; 0.023575516)0.290756-70.92%
Mixed Unicode0.865691406 (0.013355469; 0.001882812)0.862647125 (0.009561219; 0.012480469)0.996483-0.35%
Shared prefixes1.442992187 (0.014175781; 0.060458313)0.425919594 (0.002939461; 0.012159187)0.295164-70.48%
Dense suffixes2.35503125 (0.020028625; 0.039721313)2.357835937 (0.02818225; 0.098164062)1.001191+0.12%
High-output, no hit4.63714575 (0.017401; 0.130124875)4.655984375 (0.0189115; 0.163510375)1.004063+0.41%
High-output, sparse4.782875 (0.043520875; 0.03275)4.759760375 (0.030213625; 0.098999875)0.995167-0.48%
Duplicate patterns2.288026062 (0.009601563; 0.022078063)1.725445312 (0.031473938; 0.0095)0.75412-24.59%
Early hit7.3808335 (0.04828125; 0.234719)2.25433075 (0.05160675; 0.032132812)0.30543-69.46%
Late hit7.4371145 (0.02235425; 0.1510415)2.260109375 (0.037114625; 0.019760375)0.303896-69.61%
10k patterns1.967362 (0.0115755; 0.017362)0.601537109 (0.002729172; 0.005005203)0.305758-69.42%
Long text20.820208 (0.292167; 0.155749)20.587333 (0.39925; 0.385)0.988815-1.12%

Timing cells show median ms (within-round MAD; between-round MAD). MAD measures variation, not a confidence interval. — means that statistic was not recorded.

benchmarks-optimization.json · 2026-09-23 · 5 independent rounds · 0d10f03

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T07:35:25.510Z
Source revision
0d10f03bade9609faf6bbe086b0dd4666452c4e0
Working tree changes
true
Baseline
b01c9f2
Implementation SHA-256
3b9119908bfda141b7ebba8f291ebba40f285cb04bbde0caadb87781cade0e36
Baseline SHA-256
c0e85759b5226525ba51f7dc1f95dc427340118dca47fc93c72d613e6e46cdbf
Corpus SHA-256
4afa3eee0768ace1840771227bd94753d446ab82a09bbaf11d2acf1834462c5e
Report SHA-256
00e2cd3c6630174fa4be71ff03169a4317e0650f9b8d5856cb6fc81c07b8239f
Later targeted rechecks and remaining tradeoffs

The scan chart keeps its original five-round snapshot. Later measurements below use their own implementation fingerprints and are not spliced into it. Repeated warm construction of the ordinary small dictionary changed by 7.3% (positive means slower). High-output dictionaries use native full enumeration even on no-hit text, so ASCII gains are not universal.

Exact measurements and variation
ScenarioOperationBefore · msAfter · msTime changeRounds / source
Early Unicodeload0.007536184 (0.000202433; 0.000046631)0.007769521 (0.000126221; 0.000037882)+3.1%7 · scanRecheck
Early Unicodebuild0.006296193 (0.000046499; 0.000082372)0.0060964 (0.000044271; 0.00004863)-3.17%7 · scanRecheck
Early Unicodematch0.000103466 (0.000000839; 0.000003649)0.000100652 (0.000000945; 0.000003679)-2.72%7 · scanRecheck
Mixed Unicodeload0.161373859 (0.002421387; 0.001249348)0.160725586 (0.001869141; 0.002076008)-0.4%7 · scanRecheck
Mixed Unicodebuild0.162988445 (0.001462242; 0.001569176)0.154940594 (0.001020508; 0.000681969)-4.94%7 · scanRecheck
Mixed Unicodematch0.003720205 (0.000103099; 0.000160105)0.00419518 (0.000515127; 0.000273702)+12.77%7 · scanRecheck
Shared prefixesload1.019778656 (0.038187469; 0.019308594)1.076451844 (0.037391937; 0.027854188)+5.56%7 · scanRecheck
Shared prefixesbuild1.314447938 (0.019407563; 0.023204406)0.849103516 (0.008429687; 0.030935547)-35.4%7 · scanRecheck
Shared prefixesmatch0.000300666 (0.000001889; 0.000009721)0.000310079 (0.000001184; 0.000011546)+3.13%7 · scanRecheck
Duplicate patternsload0.056904215 (0.001910727; 0.000343344)0.057346436 (0.002123615; 0.001427814)+0.78%7 · scanRecheck
Duplicate patternsbuild0.036539266 (0.000353801; 0.000282308)0.045132162 (0.000180543; 0.001015463)+23.52%7 · scanRecheck
Duplicate patternsmatch0.00009635 (0.000000731; 0.000001887)0.000096013 (0.000001251; 0.000003813)-0.35%7 · scanRecheck
Duplicate patternsload0.0510448 (0.000971191; 0.000046184)0.051154216 (0.000773642; 0.000258504)+0.21%7 · builderRecheck
Duplicate patternsbuild0.035663778 (0.000324342; 0.000484985)0.017146688 (0.000130717; 0.000104512)-51.92%7 · builderRecheck
Duplicate patternsmatch0.000097522 (0.000000668; 0.000002916)0.000099024 (0.000000907; 0.000001781)+1.54%7 · builderRecheck
Ordinary textload0.074622314 (0.002341635; 0.001869955)0.078218018 (0.003306396; 0.00222526)+4.82%7 · builderRecheck
Ordinary textbuild0.075951334 (0.001940672; 0.002001219)0.081459799 (0.001128416; 0.000841391)+7.25%7 · builderRecheck
Ordinary textmatch0.000145013 (0.000002099; 0.000007323)0.000146319 (0.0000032; 0.000005473)+0.9%7 · builderRecheck
Shared prefixesload1.012390625 (0.029386719; 0.030472656)1.033446625 (0.023977906; 0.045339844)+2.08%7 · builderRecheck
Shared prefixesbuild1.26889975 (0.042160187; 0.031625)0.841124344 (0.031281234; 0.051948562)-33.71%7 · builderRecheck
Shared prefixesmatch0.000313238 (0.000002728; 0.000009483)0.000354697 (0.000012394; 0.000044048)+13.24%7 · builderRecheck
Mixed Unicodeload0.161232094 (0.002578449; 0.001061688)0.158745281 (0.003340008; 0.001036133)-1.54%7 · builderRecheck
Mixed Unicodebuild0.164593262 (0.00159798; 0.001666504)0.15644059 (0.002091469; 0.00152018)-4.95%7 · builderRecheck
Mixed Unicodematch0.004181345 (0.000354461; 0.000251313)0.003797536 (0.000316915; 0.000310079)-9.18%7 · builderRecheck
Shared prefixesmatch0.000295103 (0.000003017; 0.000013225)0.000304079 (0.000003312; 0.000004858)+3.04%7 · presenceRecheck

benchmarks-optimization-recheck.json · 2026-09-23 · 7 independent rounds · 0d10f03

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T07:50:21.300Z
Source revision
0d10f03bade9609faf6bbe086b0dd4666452c4e0
Working tree changes
true
Baseline
b01c9f2
Implementation SHA-256
3b9119908bfda141b7ebba8f291ebba40f285cb04bbde0caadb87781cade0e36
Baseline SHA-256
b6d995a840e4962a368f3f098a3e2c013a05f294ec8860efcd549ce9a5ff16a3
Corpus SHA-256
4afa3eee0768ace1840771227bd94753d446ab82a09bbaf11d2acf1834462c5e
Report SHA-256
ba12ed87faa1dc14127bf7be75530b5d1477969c874c8f99e461320b2df08680

benchmarks-final-builder-recheck.json · 2026-09-23 · 7 independent rounds · dd97451

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:16:31.795Z
Source revision
dd97451efdce9586bbe7d3f442a410ed77d07853
Working tree changes
true
Baseline
b01c9f2
Implementation SHA-256
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c
Baseline SHA-256
59e4199637e07de27cf118aee97e5cc736356eaf5813d2017811c39aa4e937c4
Corpus SHA-256
4afa3eee0768ace1840771227bd94753d446ab82a09bbaf11d2acf1834462c5e
Report SHA-256
4c02cf008470fc6b27a6d48f339ee593b22e476f3f268ef9406241caf7bbdcfe

benchmarks-presence-final-recheck.json · 2026-09-23 · 7 independent rounds · dd97451

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:20:14.774Z
Source revision
dd97451efdce9586bbe7d3f442a410ed77d07853
Working tree changes
true
Baseline
b01c9f2
Implementation SHA-256
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c
Baseline SHA-256
3fc0b1a2891ab6fbc993d76904205615631e871dc262d41d3dac990d13b34725
Runner SHA-256
f45aeb0a9c3eda6c4b9fd27056167d3888c22f8a8c66f616ab829ea901243c55
Corpus SHA-256
4afa3eee0768ace1840771227bd94753d446ab82a09bbaf11d2acf1834462c5e
Report SHA-256
842c493eae1c6965b7456f24f639aea7fa86272975a13dcdd461c496c3a62a38

v1, v2 and optimized v3

With independent UTF-16 ranges as the shared output, optimized v3 is faster than v2 in 14 of 14 scenarios. v1 still wins on some ASCII inputs. Results that fail the correctness check have no bars or speed ratios.

Independent ranges · lower is faster · v2 = 1×. v1 is not comparable for emoji, ZWJ, combining marks and CRLF.

Independent range timings · median ms (MAD; between-round MAD)
Scenariov1 · msv2 · msOptimized v3 · msRounds / source
Ordinary text0.671835937 (0.007359375; 0.019706375)3.49615625 (0.027041625; 0.029947875)0.598543625 (0.005460937; 0.003548172)5 · original
No matches0.421351562 (0.004225906; 0.008166016)4.42000525 (0.039885375; 0.0384895)0.598173172 (0.005952469; 0.024811844)7 · recheck
Shared prefixes0.475947906 (0.006143219; 0.009919281)2.524388 (0.020815125; 0.046349)0.393973313 (0.003625977; 0.007260742)5 · original
Dense suffixes3.114309938 (0.021072938; 0.015197875)3.259916688 (0.0251745; 0.051653688)2.305966125 (0.025445312; 0.0263125)5 · original
Duplicate patterns1.871252625 (0.017622375; 0.054755188)3.55315625 (0.02338525; 0.03960425)1.631329437 (0.016760406; 0.011783875)5 · original
Early hit1.580188812 (0.033903625; 0.009697906)13.1050625 (0.1155415; 0.08775)2.129585938 (0.015182313; 0.073263)7 · recheck
Late hit1.568641938 (0.013188812; 0.041936187)12.9421045 (0.0714375; 0.1565215)2.169085938 (0.027036438; 0.052179688)7 · recheck
10k patterns0.819513016 (0.022947266; 0.032115234)3.840359375 (0.053541625; 0.099510375)0.598176438 (0.006532563; 0.005749344)5 · original
Long text12.49685425 (0.09892725; 0.2773645)60.378291 (1.155417; 0.773166)9.545948 (0.07855225; 0.21780225)5 · original
Chinese2.33740625 (0.043601625; 0.076854188)4.956802 (0.06201575; 0.082036375)2.350195313 (0.0244115; 0.056028625)5 · original
EmojiNot comparable1.875125 (0.031598937; 0.0247005)0.809717438 (0.003578125; 0.009024719)5 · original
ZWJ sequencesNot comparable0.700683594 (0.004184891; 0.005352203)0.331774742 (0.002745773; 0.001072594)5 · original
Combining marksNot comparable2.134664063 (0.026484375; 0.01678125)1.042622375 (0.008112; 0.008574188)5 · original
CRLFNot comparable2.288255187 (0.019752563; 0.003966125)0.570280609 (0.004173156; 0.010173844)5 · original

Native v1/v2 search returns grouped output; v3 returns independent match objects. The native timings below measure different output work and should not be read as equivalent throughput.

Native output timings · median ms (MAD; between-round MAD)
Scenariov1 · msv2 · msOptimized v3 · msRounds / source
Ordinary text0.479438141 (0.007430984; 0.004863266)1.701596375 (0.018164062; 0.020921937)0.610501953 (0.004858719; 0.014290375)7 · recheck
No matches0.423757812 (0.005669266; 0.006125)2.1667995 (0.017763; 0.02735675)0.598205719 (0.007033203; 0.028513016)7 · recheck
Shared prefixes0.436317703 (0.004397125; 0.000654312)1.302658875 (0.008703156; 0.014859406)0.392411781 (0.002458328; 0.011767258)5 · original
Dense suffixes0.007156077 (0.000054026; 0.000077382)0.051514242 (0.000309977; 0.000531006)2.313322875 (0.032333313; 0.012132875)7 · recheck
Duplicate patterns0.327894531 (0.00320475; 0.001456055)0.943231781 (0.005602844; 0.011592437)1.623438813 (0.014154938; 0.016690125)7 · recheck
Early hit1.584460937 (0.019053406; 0.014001313)6.58317725 (0.04205225; 0.0798855)2.144432313 (0.017877625; 0.087416625)7 · recheck
Late hit1.571467438 (0.013057313; 0.020328125)6.478395875 (0.0583645; 0.109989625)2.182192687 (0.015388; 0.026875)7 · recheck
10k patterns0.65314975 (0.004081359; 0.016722016)1.886552125 (0.0406745; 0.010877562)0.599035156 (0.005404297; 0.011255859)5 · original
Long text8.896427 (0.0968125; 0.1152395)29.96625 (0.276334; 0.093042)9.651927 (0.06138525; 0.2726145)7 · recheck
Chinese1.906877563 (0.02800525; 0.02590625)2.318304687 (0.052122375; 0.033828125)2.413601563 (0.051817688; 0.018005188)7 · recheck
EmojiNot comparable1.018970031 (0.008847656; 0.015799438)0.819953125 (0.005609375; 0.018988281)5 · original
ZWJ sequencesNot comparable0.383055344 (0.00359375; 0.000662766)0.331748703 (0.002734055; 0.001452789)5 · original
Combining marksNot comparable1.077026031 (0.004104156; 0.013281219)1.052846375 (0.010964875; 0.005266937)5 · original
CRLFNot comparable1.088936187 (0.006821625; 0.011173188)0.584257156 (0.007115234; 0.009666672)5 · original

A seven-round recheck replaces a complete scenario/operation group across all three versions only after source, environment, runner and corpus validation. Remaining groups keep five rounds. Memory measurements stay with the original report.

benchmarks-versions-optimization.json · 2026-09-23 · 5 independent rounds · dd97451

Environment and full provenance
node
v24.18.0
pnpm
pnpm@12.5.1
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:22:10.112Z
Source revision
dd97451efdce9586bbe7d3f442a410ed77d07853
Working tree changes
true
Implementation SHA-256
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c
Runner SHA-256
e557a2c3f4c207fb5a8f2dbf24a9da15572830e94a005716559218cb6323f7ea
Corpus SHA-256
8dbac3966d9f23c4047c59576d55779948d57a39c7603acdf7b748506f701d4d
Report SHA-256
f9df675eeca635f032eb77e18f107bd6ba7d8031194ee4a4fcf7dcb2d6dcd9f3
v1 · 1.1.0
92e364bded18733ea20c25d2ba2773677970600be6d65da05fa325267a19d2c1
v2 · 2.0.4
8de77ed31903160adb53c77cf4aff80032144f685710c719c5490e592c9d7397
current · 3.2.0
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c

benchmarks-versions-optimization-recheck.json · 2026-09-23 · 7 independent rounds · dd97451

Environment and full provenance
node
v24.18.0
pnpm
pnpm@12.5.1
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:31:59.230Z
Source revision
dd97451efdce9586bbe7d3f442a410ed77d07853
Working tree changes
true
Implementation SHA-256
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c
Runner SHA-256
e557a2c3f4c207fb5a8f2dbf24a9da15572830e94a005716559218cb6323f7ea
Corpus SHA-256
8dbac3966d9f23c4047c59576d55779948d57a39c7603acdf7b748506f701d4d
Report SHA-256
ef2bb327ec120146210728cadba8d622c0498530b18a4072086db5daace5f1c2
v1 · 1.1.0
92e364bded18733ea20c25d2ba2773677970600be6d65da05fa325267a19d2c1
v2 · 2.0.4
8de77ed31903160adb53c77cf4aff80032144f685710c719c5490e592c9d7397
current · 3.2.0
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c

Cold construction at scale

At 1,000,000 patterns, cold construction time changed by -59% and peak RSS by -71.3%. These are seven-process medians; cold process construction is distinct from repeated warm construction.

Construction time

Peak process RSS

Patterns on the horizontal axis. Peak RSS includes the process runtime and temporary construction state; it is not the retained dictionary size. The historical baseline loads modules through data URLs, so module-loader storage also differs within this whole-process measurement.

Exact measurements and variation
PatternsBefore · msAfter · msTime changeBefore MAD · msAfter MAD · msBefore RSS · MiBAfter RSS · MiBRSS changeBefore RSS MAD · MiBAfter RSS MAD · MiBBefore heap · MiBAfter heap · MiBBefore buffers · MiBAfter buffers · MiB
10,00031.937520.737292-35.07%0.6406251.149459106.29687571.625-32.62%0.6406250.4531250.546120.5414511.6025161.602516
100,000186.38487592.04775-50.61%2.6110842.525708407.109375140.375-65.52%0.6250.218753.4950793.49029516.02207216.022072
1,000,0001,945.30275797.322209-59.01%67.38412520.2749582,300.21875660.15625-71.3%2.4531251.23437534.21742234.212784160.217628160.217628

benchmarks-builder-final.json · 2026-09-23 · 7 independent rounds · dd97451

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:20:48.462Z
Source revision
dd97451efdce9586bbe7d3f442a410ed77d07853
Working tree changes
true
Baseline
b01c9f2
Implementation SHA-256
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c
Baseline SHA-256
18cd42aabc95d9d3dfcd94ae9983fdd8d1ad7e2908860f26cc36f38136e28dbf
Runner SHA-256
05d461798498b3528241cf8dc5e088b4297f93da826d6caeeab01939ba2c7b85
Report SHA-256
ed7f42a9f1abb3eef12296b678b40edeead71419619cba954d7371fc20f2832a

Memory retained by the dictionary

The dedicated retention run disables timing and averages multiple live dictionary copies. The bars compare retained JS heap; ArrayBuffer storage is reported separately in bytes. Buffer measurements are unchanged in 18 of 18 scenarios.

After / before · baseline = 1× · zero-based scale to avoid exaggerating small differences

Exact measurements and variation
ScenarioBefore heap · BAfter heap · BHeap changeBefore buffers · BAfter buffers · B
Tiny ASCII3,929.9043,902.088-0.71%00
CRLF4,366.9524,368.912+0.04%00
ASCII + combining4,192.5844,191.728-0.02%00
Unicode at start4,148.2564,146.648-0.04%00
ASCII prefix4,081.6484,066.56-0.37%00
Early Unicode3,907.4723,900.928-0.17%00
Ordinary text13,854.67213,817.168-0.27%8,1568,156
No matches29,062.8429,109.44+0.16%20,35620,356
Mixed Unicode9,098.689,102.552+0.04%7,2607,260
Shared prefixes55,875.8455,757.2-0.21%264,568264,568
Dense suffixes8,500.0488,497.984-0.02%3,8683,868
High-output, no hit5,992.086,041.376+0.82%328328
High-output, sparse5,992.086,041.392+0.82%328328
Duplicate patterns14,492.59214,432.592-0.41%1,6001,600
Early hit3,907.4723,900.928-0.17%00
Late hit3,907.4723,900.928-0.17%00
10k patterns498,346.4496,666.4-0.34%1,680,3601,680,360
Long text4,845.1524,823.632-0.44%00

benchmarks-retained-optimization.json · 2026-09-23 · 7 independent rounds · 0d10f03

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:13:54.285Z
Source revision
0d10f03bade9609faf6bbe086b0dd4666452c4e0
Working tree changes
true
Baseline
b01c9f2
Implementation SHA-256
6716d18808b34e066dc30eaaaa8b90d773adc567feda47150f18e51b0283296c
Baseline SHA-256
68cd0ffc3df077980b83ce045256e4627b9c006a0d086f334c32492bb13ffb18
Corpus SHA-256
4afa3eee0768ace1840771227bd94753d446ab82a09bbaf11d2acf1834462c5e
Report SHA-256
71bc3027f7f0ff0101008e492526541a79f895ec517aff726c158a9e87a32ad0

10,000-pattern dictionary across versions

Stacked components share the same unit: 1 MiB = 1,048,576 bytes. This excludes returned result objects and process peak RSS.

Dictionary memory by version
VersionJS heap · BArrayBuffer · BCombined · MiB
v17,366,382.407.02513
v27,366,56007.025299
Optimized v3496,567.21,680,3602.07608

benchmarks-versions-optimization.json · 2026-09-23 · 5 independent rounds · dd97451

Environment and full provenance
node
v24.18.0
pnpm
pnpm@12.5.1
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T08:22:10.112Z
Source revision
dd97451efdce9586bbe7d3f442a410ed77d07853
Working tree changes
true
Implementation SHA-256
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c
Runner SHA-256
e557a2c3f4c207fb5a8f2dbf24a9da15572830e94a005716559218cb6323f7ea
Corpus SHA-256
8dbac3966d9f23c4047c59576d55779948d57a39c7603acdf7b748506f701d4d
Report SHA-256
f9df675eeca635f032eb77e18f107bd6ba7d8031194ee4a4fcf7dcb2d6dcd9f3
v1 · 1.1.0
92e364bded18733ea20c25d2ba2773677970600be6d65da05fa325267a19d2c1
v2 · 2.0.4
8de77ed31903160adb53c77cf4aff80032144f685710c719c5490e592c9d7397
current · 3.2.0
c7af20de2e8a6a0064b3755ef656d653b0e6d469429ac614a7f0c03d5bc32a6c

Long streams with continuous consumption

The caller consumes every output batch immediately. Points show post-GC heap growth relative to a baseline taken after creating the dictionary and input. This excludes their preexisting memory and caller-retained outputs, as well as native ICU allocations and peak RSS. Straight lines only connect measured input sizes; runtime and JIT noise remain included.

all

leftmost-longest

Before EOF, optimized leftmost-longest had already emitted 79,997 of 80,000 matches. The table also shows retained memory with the handle still held after finish and cancel.

Exact measurements and variation
Strategy / snapshotUTF-16Heap growth · KiBArrayBuffer growth · KiBEmitted before EOFFinal matchesClosed heap growth · KiBClosed buffer growth · KiB
all · Before40,0002,031.015625011,997120,00014,666.7578130
all · Before120,0003,848.695313035,997120,00014,666.7578130
all · Before400,00014,707.843750119,997120,00014,666.7578130
all · After40,000263.6875011,997120,000158.468750
all · After120,000268.117188035,997120,000158.468750
all · After400,000264.0078130119,997120,000158.468750
leftmost-longest · Before40,0002,899.5703130080,00023,179.2031250
leftmost-longest · Before120,0006,388.9296880080,00023,179.2031250
leftmost-longest · Before400,00023,208.250080,00023,179.2031250
leftmost-longest · After40,000271.14062507,99780,000158.43750
leftmost-longest · After120,000275.679688023,99780,000158.43750
leftmost-longest · After400,000271.09375079,99780,000158.43750

benchmarks-stream-optimization.json · 2026-09-23 · 3 independent rounds · b6ebdce

Environment and full provenance
node
v24.18.0
platform
darwin
arch
arm64
cpu
Apple M4 Max
icu
78.3
unicode
17.0
Measured at
2026-09-23T06:23:33.062Z
Source revision
b6ebdce7f04a8c511060a9af9a65ff64e9c9c04f
Working tree changes
true
Baseline
b01c9f22b2566b3a6058b41b05564b214899c8d7
Implementation SHA-256
593af04bb53db03a3dd84c0be75c30ec04dc51cbd6e863af74db75d6a0e1fb7a
Baseline SHA-256
8c4bb499ac67a4b7917f264e0f84b36c5d88a3ba7cd0f5cdb0c75fd87b9b3566
Report SHA-256
0da839a7d97d632f9646508c5cc4a96da35371bb9e689a4013659235b573d389

Backend choices ​

Start with the default compact backend. /fast opts into double-array storage; /unicode-fast combines that backend with full folding. The default import does not load the optional compiler or folding data.

ts
import FastAhoCorasick from 'modern-ahocorasick/fast'

const matcher = new FastAhoCorasick(['cat'])
matcher.search('cat')[0]?.start // 0
matcher.getStats().backend // 'double-array'

Measured tradeoffs ​

/fast is an explicit double-array backend, not a universal speed guarantee. It can reduce ArrayBuffer storage while increasing JavaScript heap usage; cursor overhead may dominate scans. In the snapshot before the streaming, scanner and builder optimizations, on Node 24.18.0 / Apple M4 Max, the 10,000-pattern ASCII comparison measured 28.23 ms construction and 4.34 ms search for /fast, versus 13.61 ms and 2.00 ms for the default backend. Retained heap was 3.52 MiB versus 0.47 MiB; buffers were 1.18 MiB versus 1.60 MiB. These are three-round medians, not measurements of the optimized build or a prediction for other dictionaries. Boundaries and folding use the general cursor, so filtered count() does enumerate accepted outputs. The default exact counting and presence paths retain their allocation-light implementation.

The feature comparison targets @monyone/aho-corasick@1.5.10 and @tanishiking/aho-corasick@0.0.1. Their index, duplicate and Unicode contracts differ; this package preserves its own ranges and semantics rather than copying defects or method aliases. Run pnpm benchmark:external for the printable-ASCII comparison, including normalized independent ranges, native results, build costs and memory.

Run pnpm benchmark:versions to compare pinned npm v1.1.0 and v2.0.4 against the current local default entry: construction, native search, conversion to independent ranges and retained memory. Historical Unicode cases with incorrect results receive no speed ratios. The optimized-build version comparison includes the current measurements; the earlier v1/v2/v3 report remains a historical snapshot.

In the optimized build's five-round comparison, independent range output was faster than v2 in all 14 fixtures. Seven-round rechecks confirmed v1 still scanned some ASCII inputs faster, and historical native grouped output has different allocation costs. The 10,000-pattern dictionary retained about 2.08 MiB of heap plus buffers, versus 7.03 MiB for either older version. These results support choosing by the output contract and workload, rather than a universal version ranking.

The streaming, scanning and construction report records the subsequent changes against b01c9f2: incremental transformed-stream retention, an 18-scenario scanner comparison, retained-dictionary measurements, and cold construction at 10,000–1,000,000 patterns. It distinguishes repeated warm construction, retained heap, ArrayBuffer storage and construction peak RSS, with raw process results, implementation fingerprints and targeted rechecks.

Full enumeration uses native grapheme segmentation for dictionaries that can emit many matches at one state. This avoids extra overhead in dense output, but those dictionaries also use that path when an input has few or no matches. ASCII acceleration therefore depends on the dictionary as well as the text; measure representative no-hit inputs too. Counting and selected-match scans keep their own paths.

Reproduce and interpret ​

sh
pnpm benchmark
pnpm benchmark:external
pnpm benchmark:versions
pnpm benchmark:scale
pnpm benchmark:stream
pnpm benchmark:docs

Run these commands from the repository. Compare build and scan time, retained heap and buffers separately; getStats().typedArrayBytes is not total heap. Filtering, folding, result arrays and longest-first have costs beyond the default exact scan. The workbench includes debounce, Worker and transfer time, so its display is not a library benchmark.

Sources: Extension benchmarks · v2/v3 benchmarks · ASCII benchmarks · Workbench measurements

MIT · Based on BrunoRB/ahocorasick