This benchmark compares IPRangeList with Node.js net.BlockList using IPv4 and IPv6 CIDR range CSV files.
CSV parsing and lookup address setup happen before timing starts. IPv4 prefixes are queried as IPv4-mapped IPv6 addresses so both implementations are measured in one combined address space. The benchmark measures these workloads:
- importing the full dataset into a new list;
- checking present-only, missing-only, and mixed address sets after the full dataset has been imported;
- importing the dataset in batches, with present-only, missing-only, and mixed checks between batches.
The input file must be a CSV with a header row and one CIDR range per row. The benchmark reads the first column only, so both of these formats work:
prefix
192.0.2.0/24
198.51.100.0/24prefix,source
2001:db8::/32,example
2001:db8:abcd::/48,exampleThe default benchmark loads both generated files. Use --ipv4-file and --ipv6-file to override them.
The default inputs are generated from Manycast LACES anycast prefix data:
npm run benchmark:prepareBuild the package before running the benchmark. The script imports the built ESM entry point from dist/.
npm run build
npm run benchmarkBy default, the benchmark loads both IPv4 and IPv6 data from benchmark/ipv4-ranges.csv and
benchmark/ipv6-ranges.csv.
You can also run it as node --expose-gc benchmark/benchmark.js; the script tries to enable gc itself and prints a
tip when the runtime still needs the flag.
Options:
--ipv4-file <csv>sets the IPv4 input CSV. The default isbenchmark/ipv4-ranges.csv.--ipv6-file <csv>sets the IPv6 input CSV. The default isbenchmark/ipv6-ranges.csv.--package <all|ip-range-list|blocklist>selects which implementation to run. The default isall.--runs <number>sets the number of measured runs. The default is7.--warmups <number>sets the number of warmup runs before measurement. The default is2.--large-checks <number>sets the number of lookups after full import. The default is1000000.--chunks <number>sets the number of import batches for the interleaved workload. The default is100.--checks-per-chunk <number>sets the number of lookups after each import batch. The default is100.--query-profile <all|present|missing|mixed>selects which query profile to run. The default isall.--mixed-miss-rate <number>sets the missing-address share in the mixed profile. The default is0.8.--update-readmeupdates the published result tables inREADME.mdandbenchmark/README.md. It requires all implementations and query profiles.--verboseprints progress output.
The script prints a results table and saves the full settings, hit counts, and average, and minimum
timings to benchmark/results-YYYYMMDD-HHMMSS.json.
To rerun without downloading data, or to run with custom files, use the run-only script:
npm run benchmark:run -- --ipv4-file path/to/ipv4-ranges.csv --ipv6-file path/to/ipv6-ranges.csvFull import measures how long it takes to add every prefix from the CSV file to a new list.
Large lookup imports the full dataset, then checks three query profiles. present contains only addresses derived from
the dataset prefixes. missing contains only generated addresses that are not present in the dataset. mixed contains
20% present addresses and 80% missing addresses by default. With the default settings, each profile runs 1,000,000
checks.
Interleaved import/lookups splits the dataset into batches, imports one batch at a time, and runs lookups after each batch. Present queries in this workload only use prefixes already imported in the current or previous batches. With the default settings, this uses 100 batches and 100 lookups after each batch for each selected profile.
Missing addresses are generated with a seeded pseudo-random generator. The generator preserves the source dataset's IPv4/IPv6 prefix ratio, maps generated IPv4 misses to IPv4-mapped IPv6 addresses, and rejects generated addresses that fall inside the loaded ranges.
The published results were collected with Node.js v24.6.0 on Windows 11 x64, Intel Core Ultra 9 275HX by running
npm run benchmark. The input data was generated from the unfiltered first column of the Manycast LACES anycast prefix
data and contained 55,473 prefixes: 41,207 IPv4 prefixes and 14,266 IPv6 prefixes.
The benchmark used 7 measured runs after 2 warmup runs. Each large lookup profile ran 1,000,000 checks. The interleaved workload used 100 import batches with 100 checks after each batch. The mixed profile used 20% present addresses and 80% missing addresses. Table values are averages in milliseconds.
| Scenario | Profile | Checks | ip-range-list |
node:net BlockList |
Result |
|---|---|---|---|---|---|
| Full import | - | 55,473 prefixes | 54.09 ms | 40.36 ms | BlockList 1.34x faster |
| Large lookup after import | present | 1,000,000 | 1,472.24 ms | 184,395.46 ms | ip-range-list 125.25x faster |
| Large lookup after import | missing | 1,000,000 | 1,568.54 ms | 394,476.87 ms | ip-range-list 251.49x faster |
| Large lookup after import | mixed | 1,000,000 | 1,609.40 ms | 356,680.64 ms | ip-range-list 221.62x faster |
| Interleaved import/lookups | present | 10,000 | 71.01 ms | 1,009.32 ms | ip-range-list 14.21x faster |
| Interleaved import/lookups | missing | 10,000 | 96.28 ms | 2,023.87 ms | ip-range-list 21.02x faster |
| Interleaved import/lookups | mixed | 10,000 | 98.54 ms | 1,818.27 ms | ip-range-list 18.45x faster |