radix3

A lightweight, dependency-free radix-tree router for JavaScript and TypeScript, matching static, parameterized, and wildcard routes with fast, precomputable lookups.

Library
npm
v1.1.2
745stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
73/100Good
Development Activity72
Maintenance76
Community48
Maturity56
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture74
Code Quality78
Innovation72
Learning Curve45

radix3 is a lightweight JavaScript router built on a radix tree (compressed prefix tree) data structure, giving it fast route insertion and lookup with a minimal memory footprint. It supports static paths, named parameters (:name), and wildcard segments (** and **:name), returning matched route data alongside any extracted params on lookup.

Beyond the core createRouter/insert/lookup/remove API, radix3 ships a toRouteMatcher utility that compiles a router’s tree into a flat lookup table capable of returning every route that matches a given path, not just the most specific one, ordered from least to most specific. This matcher can also be exported to a plain JSON object and rehydrated later, letting consumers precompute routing tables at build time and skip tree construction at runtime. It has no runtime dependencies and ships as dual ESM/CJS builds with TypeScript types, making it a drop-in routing core for frameworks and CLIs. It was originally based on charlieduong94/radix-router and is maintained by the UnJS collective.

What You Get

  • A dependency-free createRouter() factory with insert, lookup, and remove methods operating on a radix tree
  • Support for static, :named placeholder, and **/**:name wildcard route segments with automatic precedence (static > placeholder > wildcard)
  • A toRouteMatcher/matchAll API that returns every route matching a path, ordered least-to-most specific, useful for merging route-level config
  • exportMatcher/createMatcherFromExport to serialize a compiled matcher to JSON and rehydrate it without rebuilding the tree
  • Dual ESM/CJS builds with bundled TypeScript types and zero runtime dependencies

Common Use Cases

  • Routing engine inside server frameworks and meta-frameworks that need fast static and dynamic path matching
  • CLI or build tools that need to match file paths against glob-like route patterns
  • Config/rule systems where multiple overlapping patterns must all be resolved and merged for a given path via toRouteMatcher
  • Precompiling routing tables at build time and shipping the exported JSON to avoid runtime tree construction in edge/serverless environments

Under The Hood

Architecture radix3’s architecture centers on two independent modules that share only the RadixRouter tree shape defined in src/types.ts: src/router.ts implements the mutable radix tree itself (createRouter, insert, lookup, remove) using a RadixNode with a children Map, a placeholderChildren array, and a single wildcardChildNode, plus a staticRoutesMap fast-path cache for fully static routes; src/matcher.ts is a separate read-only projection (toRouteMatcher/_routerNodeToTable) that walks the same root node once to build a flattened route table of static/wildcard/dynamic maps, with its own independent matchAll algorithm rather than reusing lookup’s logic. This is a layered, single-purpose design (build tree, then optionally derive a matcher) with no external state; the whole library is a few hundred lines split across router.ts, matcher.ts, and types.ts, and because matcher.ts reads router internals directly (node.type, node.children, node.wildcardChildNode) rather than through an abstraction, a change to the core RadixNode shape would require both files to change in lockstep.

Tech Stack radix3 has zero runtime dependencies; its devDependencies are entirely tooling: TypeScript for types, Vitest for tests, unbuild to produce dual ESM (dist/index.mjs) and CJS (dist/index.cjs) builds with bundled .d.ts types, ESLint (via eslint-config-unjs) and Prettier for linting/formatting, changelogen for release/changelog automation, and a small benchmark suite (0x, autocannon, benchmark, listhen) used to profile the router against an HTTP server. It targets any JavaScript runtime (Node, browsers, edge) since the source touches no platform-specific APIs.

Code Quality Tests live in tests/router.test.ts and tests/matcher.test.ts, run under Vitest with inline snapshot assertions, and are substantial relative to the source size, covering the README’s own examples plus edge cases like trailing-slash handling, wildcard precedence, and static-route short-circuiting. Types are moderately strict for a library this size, including a params-reserved-key guard expressed at the type level. Error handling is minimal by design: misses return null/false rather than throwing. Linting runs through eslint-config-unjs, an opinionated shared config, with an autofix CI bot (autofix.ci) alongside a standard test/lint CI workflow.

API Design radix3’s public surface is intentionally small: a single createRouter(options) factory returns an object with insert/lookup/remove methods operating on plain strings and data objects, so the entire onboarding path is install, import, insert, lookup, with no classes, decorators, or build step required. The one API wrinkle is the reserved params key on inserted data objects, enforced only at the type level, which can surface if a consumer’s own route data happens to use that name. The auxiliary toRouteMatcher/matchAll API is a separate entry point rather than a method on the router itself, so consumers who want “all matching routes” must learn a second construct with its own export/import round-trip (exportMatcher/createMatcherFromExport) — a natural fit for its build-time-precompute use case, though it gets comparatively brief README coverage next to the core API. Overall the ergonomics favor minimalism and zero ceremony over exhaustive configurability.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search