# Ruuter Benchmark Results Each benchmark: 2s warmup, 5s measurement window. ## Environment - **Machine**: Macbook Pro (M4 Max 48GB) - **JVM**: Java 25.0.2, Clojure 1.12.4 - **ClojureScript**: 1.12.134, Node.js v24.11.1 - **Babashka**: 1.12.212 - **Jank**: 0.1 (Apr 2026) ## Runtime Comparison (Current Versions) Current versions: - **JVM (Clojure)**: v2.1.1 - **ClojureScript (Node.js)**: v2.1.1 - **Babashka**: v2.1.1 - **Jank**: v2.1.1 | Scenario | Clojure ops/s | ClojureScript (Node.js) ops/s | Babashka ops/s | Jank ops/s | |---|---:|---:|---:|---:| | Small (5) - literal first | 5,751,517 | 826,109 | 561,707 | 632,139 | | Small (5) - literal middle | 2,236,756 | 458,372 | 328,534 | 293,751 | | Small (5) - param match | 1,138,681 | 244,455 | 194,415 | 147,771 | | Small (5) - nested params | 725,794 | 159,997 | 136,953 | 95,436 | | Small (5) - wildcard | 1,038,987 | 222,914 | 205,294 | 121,320 | | Small (5) - miss (404) | 3,507,344 | 696,492 | 611,017 | 452,239 | | Medium (52) - match first | 5,464,333 | 729,185 | 559,724 | 615,761 | | Medium (52) - match middle | 947,366 | 198,538 | 167,396 | 124,459 | | Medium (52) - match last | 943,909 | 199,165 | 168,330 | 126,711 | | Medium (52) - catch-all wildcard | 1,611,263 | 339,559 | 274,306 | 191,428 | | Large (202) - match first | 5,086,938 | 668,097 | 553,183 | 606,074 | | Large (202) - match middle | 931,339 | 195,975 | 168,974 | 125,689 | | Large (202) - match last | 925,180 | 195,752 | 168,347 | 124,528 | | Large (202) - miss (404) | 2,278,714 | 443,050 | 458,547 | 338,429 | ## Analysis - **JVM (Clojure)** leads in all scenarios in this benchmark set, peaking at ~5.8M ops/sec. - **ClojureScript (Node.js)**, **Babashka**, and **Jank** are in the same general tier, with ClojureScript typically leading and Jank usually close behind. - **Babashka** and **Jank** are very close on several large-route scenarios, with Babashka slightly ahead on large miss/404. - Across runtimes, throughput stays relatively stable as route count grows, consistent with trie-based matching by path depth. ### Running benchmarks ```bash # JVM clojure -Sdeps '{:paths ["src" "bench"]}' -M -m ruuter.bench # ClojureScript (Node.js) clojure -Sdeps '{:paths ["src" "bench"] :deps {org.clojure/clojurescript {:mvn/version "1.10.879"}}}' \ -M -m cljs.main --target node --output-to bench-out/bench.js -c ruuter.bench node bench-out/bench.js # Babashka bb -m ruuter.bench # Jank jank run --module-path src:bench jank_bench_runner.jank ``` ### Route set sizes - **Small (5)**: 5 routes — typical small app (literal, params, wildcard) - **Medium (52)**: 52 routes — 1 literal + 50 parameterized + 1 catch-all wildcard - **Large (202)**: 202 routes — 1 literal + 200 parameterized + 1 catch-all wildcard