npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@thi.ng/router

v4.1.51

Published

Generic trie-based router with support for wildcards, route param validation/coercion, auth

Readme

@thi.ng/router

npm version npm downloads Mastodon Follow

[!NOTE] This is one of 211 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.

🚀 Please help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️

About

Generic trie-based router with support for wildcards, route param validation/coercion, auth.

  • Not bound to any environment, usable on both client & server side
  • Declarative route definitions, incl. wildcards for matching rest args
  • Parametric routes, each param with optional value coercion & validation
  • Route authentication handler to enable/disable routes based on other state factors
  • Fallback route redirect
  • Enforced initial route (optional)
  • Route formatting (with params & rest args)
  • Optional HTML5 history & hash fragment support

Status

STABLE - used in production

Search or submit any issues for this package

Related packages

  • @thi.ng/hdom - Lightweight vanilla ES6 UI component trees with customizable branch-local behaviors
  • @thi.ng/rdom - Lightweight, reactive, VDOM-less UI/DOM components with async lifecycle and @thi.ng/hiccup compatible

Installation

yarn add @thi.ng/router

ESM import:

import * as rou from "@thi.ng/router";

Browser ESM import:

<script type="module" src="https://esm.run/@thi.ng/router"></script>

JSDelivr documentation

Package sizes (brotli'd, pre-treeshake): ESM: 1.95 KB

Dependencies

Note: @thi.ng/api is in most cases a type-only import (not used at runtime)

Usage examples

Two projects in this repo's /examples directory are using this package:

| Screenshot | Description | Live demo | Source | |:---------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------|:----------------------------------------------------|:---------------------------------------------------------------------------------| | | Basic thi.ng/router usage with thi.ng/rdom components | Demo | Source | | | Complete mini SPA app w/ router & async content loading | Demo | Source |

API

Generated API docs

import {
    HTMLRouter, HTMLRouterOpts, EVENT_ROUTE_CHANGED,
} from "@thi.ng/router";
import { isUUID } from "@thi.ng/checks";

// router configuration
const config: HTMLRouterOpts = {
    // use hash fragment for routes
    useFragment: true,

    // fallback route (when no other matches)
    default: "home",

    // optional enforced route when router starts
    initial: "home",

    // Optional route path component separator. Default: `/`
    separator: "/",

    // Route prefix. Default: `/` (or `#/` if `useFragment` is enabled).
    // All routes to be parsed by `route()` are assumed to have this prefix.
    // All routes returned by `format()` will include this prefix.
    prefix: "#/",

    // actual route defs
    // An array of route specs which route input strings will be matched against.
    // Given routes will be pre-processed and stored in a Trie for fast matching.
    // Additional routes can be dynamically added at a later time via .addRoutes()
    routes: [
        {
            // each route MUST have an ID
            id: "home",
            // this array defines the route path items
            match: "/home",
        },
        {
            id: "user-profile",
            // this rule is parametric
            // variable items are prefixed with `?`
            match: "/users/?id",
            // coercion & validation handlers for "?id" param
            // coercion fn is applied BEFORE validator
            validate: {
                id: {
                    coerce: (x) => parseInt(x),
                    check: (x) => x > 0 && x < 100,
                },
            },
        },
        {
            id: "image",
            // this route has 2 params and matches (for example):
            // "/images/07a9d87b-c07a-42e3-82cf-baea2f94facc/xl"
            match: "/images/?id/?size",
            validate: {
                id: {
                    check: (x) => isUUID(x),
                },
                size: {
                    check: (x) => /^(s|m|l|xl)$/.test(x),
                },
            },
        },
        {
            id: "group-list",
            // matches only: "/users" or "/images"
            match: "/?type",
            validate: {
                type: {
                    check: (x) => /^(users|images)$/.test(x),
                },
            },
        },
    ],
};

// `HTMLRouter` ONLY works in browser environments
// for non-browser use cases use `Router`
const router = new HTMLRouter(config);
router.addListener(EVENT_ROUTE_CHANGED, console.log);

router.start();

Benchmarks

The below benchmarks are ported from router-benchmark, showing highly competitive results for this package. The benchmark itself can be run from the repo root like so:

bun packages/router/bench/index.ts
benchmarking: short static
        warmup... 133.48ms (0.1 runs)
        total: 113.79ms, runs: 1 (@ 1 calls/iter)
        freq: 8788202.11 ops/sec

benchmarking: static with same radix
        warmup... 166.98ms (0.1 runs)
        total: 161.89ms, runs: 1 (@ 1 calls/iter)
        freq: 6176873.20 ops/sec

benchmarking: dynamic route
        warmup... 378.30ms (0.1 runs)
        total: 374.80ms, runs: 1 (@ 1 calls/iter)
        freq: 2668082.83 ops/sec

benchmarking: mixed static dynamic
        warmup... 344.19ms (0.1 runs)
        total: 340.33ms, runs: 1 (@ 1 calls/iter)
        freq: 2938310.18 ops/sec

benchmarking: long static
        warmup... 326.61ms (0.1 runs)
        total: 327.84ms, runs: 1 (@ 1 calls/iter)
        freq: 3050259.51 ops/sec

benchmarking: wildcard
        warmup... 207.84ms (0.1 runs)
        total: 207.49ms, runs: 1 (@ 1 calls/iter)
        freq: 4819484.22 ops/sec

benchmarking: all together
        warmup... 1525.05ms (0.1 runs)
        total: 1532.24ms, runs: 1 (@ 1 calls/iter)
        freq: 652640.66 ops/sec

Authors

If this project contributes to an academic publication, please cite it as:

@misc{thing-router,
  title = "@thi.ng/router",
  author = "Karsten Schmidt",
  note = "https://thi.ng/router",
  year = 2014
}

License

© 2014 - 2025 Karsten Schmidt // Apache License 2.0