State of URL parsing performance in 2025

8 min read Original article ↗

Introduction

Daniel Stenberg (author of cURL) recently questioned Ada’s performance claims , suggesting they were “biased” and “misleading”. This post presents updated benchmark results using reproducible methodology on current hardware and software versions.

Bluesky post

Daniel Lemire and I published our methodology in an academic paper: Parsing Millions of URLs per Second . The benchmarks below follow the same approach. I’ve included real-world context using Vercel’s Black Friday data to show what these performance differences mean at scale.

About Ada

The current release is Ada v3.3.0, which is used in production by Internet Archive, Node.js, ClickHouse, Redpanda, Kong, Telegram, AdGuard, Datadog, and Cloudflare Workers. Ada v3 introduced URLPattern support alongside its URL parsing capabilities.

Ada provides two URL parser implementations optimized for different use cases: ada::url optimizes for setters (modifying URL components), while ada::url_aggregator optimizes for getters (reading URL components). The benchmarks below test both implementations to show their respective performance characteristics.

Benchmarks

I’ve run benchmarks on macOS 26 Tahoe 26.1 on my personal Mac Mini 2024 with 14 cores (10 performance and 4 efficiency cores) and 64 GB memory. These benchmarks use Ada commit 662de99d89078a60cc54fa1b696486cfcc814cff.

To reproduce these benchmarks locally, follow these commands:

# Clone the Ada repository
git clone https://github.com/ada-url/ada.git
cd ada
 
# Checkout the specific commit used in these benchmarks
git checkout 662de99d89078a60cc54fa1b696486cfcc814cff
 
# Configure the build with benchmarks enabled
cmake -B build \
  -DADA_BENCHMARKS=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DADA_USE_UNSAFE_STD_REGEX_PROVIDER=ON
 
# Build the project
cmake --build build
 
# Run the benchmarks (may require sudo for performance counter access)
sudo ./build/benchmarks/benchdata --benchmark_counters_tabular=true

This will give you a really nice table with some information about the benchmark and the data before the results such as:

loaded db: as4-1 (Apple silicon)
Loading /Users/yagiz/coding/ada/ada/ada/build/_deps/url-dataset-src/out.txt
Unable to determine clock rate from sysctl: hw.cpufrequency: No such file or directory
This does not affect benchmark measurements, only the metadata output.
***WARNING*** Failed to set thread affinity. Estimated CPU frequency may be incorrect.
2025-12-09T10:41:01-05:00
Running ./build/benchmarks/benchdata
Run on (14 X 24 MHz CPU s)
CPU Caches:
  L1 Data 64 KiB
  L1 Instruction 128 KiB
  L2 Unified 4096 KiB (x14)
Load Average: 1.67, 2.03, 3.13
ada spec: Ada follows whatwg/url
bad urls: ---------------------
ada---count of bad URLs       26
servo/url---count of bad URLs 26
whatwg---count of bad URLs    26
curl---count of bad URLs      130
-------------------------------

bytes/URL: 86.859205
curl spec: Curl follows RFC3986, not whatwg/url
curl version : 8.7.1
input bytes: 8688092
number of URLs: 100025
performance counters: Enabled
rust version : 1.91.1
zuri : OMITTED

Defaults on macOS 26 Tahoe

macOS 26 Tahoe comes with cURL 8.7.1. Using the default version of cURL, the performance of all URL parsers are as follows:

➜ sudo ./build/benchmarks/benchdata --benchmark_counters_tabular=true

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Benchmark                                            Time             CPU   Iterations        GHz cycle/byte cycles/url instructions/byte instructions/cycle instructions/ns instructions/url     ns/url      speed  time/byte   time/url      url/s
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
BenchData_BasicBench_AdaURL_href              15691123 ns     15670386 ns           44    4.28376    7.50021    651.462           36.7012            4.89336          20.962         3.18784k    152.077 554.427M/s  1.80366ns  156.665ns 6.38306M/s
BenchData_BasicBench_AdaURL_aggregator_href   10755944 ns     10742391 ns           64    4.35728    5.13727    446.219           26.5566            5.16939         22.5245         2.30668k    102.408 808.767M/s  1.23645ns  107.397ns 9.31124M/s
BenchData_BasicBench_AdaURL_CanParse           6515744 ns      6507162 ns          105    4.33009    3.10174    269.414           16.3532            5.27229         22.8295         1.42043k     62.219 1.33516G/s  748.975ps  65.0554ns 15.3715M/s
BasicBench_whatwg                             30237078 ns     30214870 ns           23    4.17769     14.328   1.24452k           79.8836            5.57535         23.2921         6.93862k    297.896 287.544M/s  3.47773ns  302.073ns 3.31046M/s
BasicBench_CURL                               76373611 ns     76343111 ns            9    4.19096    35.5292   3.08604k           190.592            5.36437         22.4819         16.5547k    736.356 113.803M/s   8.7871ns   763.24ns  1.3102M/s
BasicBench_ServoUrl                           26764394 ns     26734192 ns           26    4.22544     12.858   1.11683k           65.8217            5.11914         21.6306         5.71722k    264.312 324.981M/s  3.07711ns  267.275ns 3.74146M/s

Ada is the fastest URL parser in this comparison. The CanParse method (which only validates URL correctness without parsing all components) completes each validation in 65 nanoseconds and processes 15.37 million URLs per second, which is 11.7x faster than CURL. The aggregator_href variant (full parsing with all URL components) takes 107 nanoseconds per URL and handles 9.31 million URLs per second, which is 7.1x faster than CURL.

Ada maintains full WHATWG URL Standard compliance. CURL follows RFC 3986, which is a different specification.

Important Note on Fairness: This comparison isn’t entirely apples-to-apples. RFC 3986 is significantly simpler and can be implemented without extra memory allocations, whereas the WHATWG URL Standard is considerably more complex due to the numerous edge cases it handles (internationalized domain names, special schemes, percent encoding normalization, etc.). Ada is doing substantially more work per URL while still achieving better performance. The performance comparison would be more direct if both parsers implemented the same specification.

What This Means in Practice

To understand what these numbers mean for production systems, I looked at Vercel’s Black Friday/Cyber Monday 2025 traffic. During this period, Vercel handled 115.8 billion requests over four days, with peak traffic reaching 518,027 requests per second.

If each request requires parsing a URL (which is common in web servers for routing, logging, and request handling), here’s what the CPU requirements would look like using full URL parsing:

Using cURL:

  • Each core handles 1.31 million URLs per second
  • Peak traffic of 518,027 req/s requires 39.5% of one CPU core just for URL parsing
  • That’s 518,027 ÷ 1,310,000 = 0.395 cores

Using Ada url_aggregator:

  • Each core handles 9.31 million URLs per second
  • Same peak traffic requires only 5.6% of one CPU core
  • That’s 518,027 ÷ 9,310,000 = 0.056 cores

The difference: 33.9% of one core saved, an 86% reduction in compute resources dedicated to URL parsing.

Cost Impact at Scale

For a platform processing over 100 billion requests during a peak shopping weekend, this difference translates to meaningful savings:

  • Reduced cloud compute costs: Saving 34% of a core per server compounds across entire fleets. For a deployment with 1,000 servers handling URL-heavy workloads, this translates to 340 cores worth of compute capacity freed up for other tasks.
  • Lower power consumption: Less CPU utilization means reduced electricity costs in data centers. Even a fraction of a core, when multiplied across thousands of machines running 24/7, creates measurable energy savings.
  • Smaller cooling requirements: Reduced CPU load generates less heat, lowering cooling infrastructure demands.
  • Higher capacity on existing hardware: The freed-up compute headroom provides a buffer for traffic spikes without requiring additional provisioning.

While 34% of one core might seem small in isolation, at cloud scale these efficiency gains compound significantly. For services processing billions of URLs daily across distributed infrastructure, even fractional improvements per machine translate to substantial cost reductions and improved resource utilization across the entire fleet.

Updating to latest version of cURL

The benchmarks above used cURL 8.7.1, which ships by default with macOS 26 Tahoe. I also tested against the latest version of cURL (8.17.0) available via Homebrew. The latest version performs at 892 nanoseconds per URL and processes 1.12 million URLs per second, which is slightly slower than the default version (763ns, 1.31M URLs/s). Using the latest cURL version with Ada’s url_aggregator, the CPU core difference would be even larger—46.2% of one core with latest cURL versus 5.7% with Ada, an 88% reduction.

The performance regression between cURL 8.7.1 and 8.17.0 is notable. The latest version takes 129 nanoseconds longer per URL (892ns vs 763ns), which represents a 17% slowdown. At Vercel’s peak traffic scale of 518,027 requests per second, this difference would require 6.7% more of a CPU core just to maintain the same throughput. This shows how even minor performance regressions in parsing libraries can have measurable infrastructure cost implications at scale.

To run the benchmarks with a specific cURL version (tested with v8.17.0), use these commands:

# Install the latest cURL via Homebrew (macOS)
brew install curl
 
# Clone and configure with specific cURL version
git clone https://github.com/ada-url/ada.git
cd ada
 
cmake -B build \
    -DADA_BENCHMARKS=ON \
    -DCMAKE_BUILD_TYPE=Release \
    -DADA_USE_UNSAFE_STD_REGEX_PROVIDER=ON \
    -DCURL_INCLUDE_DIR=/opt/homebrew/opt/curl/include \
    -DCURL_LIBRARY=/opt/homebrew/opt/curl/lib/libcurl.dylib \
    -DCMAKE_FIND_FRAMEWORK=LAST \
    -DCMAKE_FIND_APPBUNDLE=LAST
 
# Build and run
cmake --build build
sudo ./build/benchmarks/benchdata --benchmark_counters_tabular=true

And here are the results:

➜  sudo ./build/benchmarks/benchdata --benchmark_counters_tabular=true

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Benchmark                                            Time             CPU   Iterations        GHz cycle/byte cycles/url instructions/byte instructions/cycle instructions/ns instructions/url     ns/url      speed  time/byte   time/url      url/s
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
BenchData_BasicBench_AdaURL_href              15803060 ns     15782000 ns           44     4.2983    7.57612    658.055           36.6275             4.8346         20.7806         3.18144k    153.097 550.506M/s  1.81651ns  157.781ns 6.33792M/s
BenchData_BasicBench_AdaURL_aggregator_href   10969095 ns     10968484 ns           64    4.24262    5.24663    455.719           26.5629            5.06284         21.4797         2.30723k    107.414 792.096M/s  1.26247ns  109.657ns 9.11931M/s
BenchData_BasicBench_AdaURL_CanParse           6682434 ns      6676443 ns          106    4.11577    3.13855    272.612           16.3542            5.21076         21.4463         1.42052k    66.2359 1.30131G/s  768.459ps  66.7477ns 14.9818M/s
BasicBench_whatwg                             31119821 ns     31092348 ns           23    4.15052    14.6009   1.26822k           79.8787            5.47082         22.7067          6.9382k    305.557 279.429M/s  3.57873ns  310.846ns 3.21703M/s
BasicBench_CURL                               89264557 ns     89178750 ns            8     4.1492    42.1106    3.6577k           233.565            5.54647         23.0134         20.2873k    881.542 97.4233M/s  10.2645ns  891.565ns 1.12162M/s
BasicBench_ServoUrl                           27290262 ns     27273400 ns           25    4.17501    12.8397   1.11524k           65.8058             5.1252         21.3977         5.71584k    267.124 318.556M/s  3.13917ns  272.666ns 3.66749M/s

Conclusion

This benchmark demonstrates that Ada delivers significant performance advantages over cURL for URL parsing, with 7.1x faster full parsing and 86% reduction in CPU utilization at scale. More importantly, it shows that URL parsing remains highly efficient even at extreme scale—requiring less than half a CPU core for over half a million requests per second.

The performance difference matters most when multiplied across large infrastructure deployments. While a single server saves only a fraction of a core, this compounds to meaningful cost savings and improved resource utilization across fleets of hundreds or thousands of machines.

Try Ada

Ada is open source and available for integration into your projects:

Ada supports C++, C, Node.js, Python, Rust, and other languages through various bindings. It’s already used in production by major platforms including Node.js, ClickHouse, Cloudflare Workers, and Datadog.

All benchmarks in this post are reproducible using the commands provided. The methodology and results are published in our peer-reviewed academic paper for full transparency.