Ruuter 2.0
Ruuter, my zero-dependency, runtime-agnostic Router for Clojure, ClojureScript and Babashka has a new release out. A pretty hefty one at that:
- Best-match routing: Routes are now matched by specificity instead of first-match-wins. Literal segments beat parameters, parameters beat optionals, optionals beat wildcards. Route order in the vector no longer matters.
- Segment trie: Routes are compiled into a trie (prefix tree) data structure for O(path-depth) matching instead of O(N) linear scan. This yields 4-380x performance improvements depending on route count and match type.
compile-routesfunction: New public function for explicit route compilation. Routes are also compiled implicitly and cached via memoization when usingroutedirectly.- Single wildcard constraint: Wildcard parameters (
:name*) must now be the last segment in a path. Multiple wildcards per path are no longer supported. - No regex: Route matching no longer uses regular expressions. Matching is done via direct string comparison of path segments against a trie.
- deps.edn only: Leiningen (
project.clj) has been retired. All build, test, and benchmark tasks usedeps.ednandbb.edn.
Massive performance improvements come with this release, which is something that’s been lacking a lot so far:
- JVM (Clojure)
- Small route sets: 1.6–4.1x faster
- Medium route sets: 39–139x faster
- Large route sets: 162–345x faster
- Peak throughput: ~9.8M ops/sec (literal match)
- ClojureScript (Node.js)
- Small route sets: 0.9–6.5x faster (literal-first is within noise; params, wildcards, and misses see large gains)
- Medium route sets: 14–40x faster
- Large route sets: 38–167x faster
- Peak throughput: ~1.3M ops/sec (literal match)
- Babashka
- Small route sets: 2.0–6.4x faster
- Medium route sets: 11–32x faster
- Large route sets: 32–182x faster
- Peak throughput: ~1.1M ops/sec (miss/404 — fast trie rejection)