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 🙏

© 2026 – Pkg Stats / Ryan Hefner

router-http

v2.0.2

Published

Simple HTTP router compatible with Express

Readme

router-http

Last version Coverage Status NPM Status

A middleware-style router similar to express router, with key advantages:

  • Predictable performance – Backed by find-my-way, a trie-based router with constant O(1) lookup time.
  • Battle-tested – Well maintained with comprehensive test coverage.
  • Lightweight – Only 1.3 kB (minifized + gzipped)

Why not Express router?

Express uses regex-based route matching that degrades linearly as routes increase:

| Routes | express@router | router-http | |--------|-----------|---------------| | 5 | ~10.7M ops/sec | ~13.7M ops/sec | | 10 | ~6.5M ops/sec | ~13.7M ops/sec | | 50 | ~1.5M ops/sec | ~11.5M ops/sec | | 1000 | ~41K ops/sec | ~10.6M ops/sec |

In contrast, router-http is backed by a trie-based implementation that maintains nearly constant performance regardless of the number of routes.

Installation

npm install router-http

Getting Started

First, define a handler for errors and unmatched routes:

const createRouter = require('router-http')

const finalHandler = (error, req, res) => {
  if (error) {
    res.statusCode = 500
    res.end(error.message)
  } else {
    res.statusCode = 404
    res.end('Not Found')
  }
}

const router = createRouter(finalHandler)

You can also pass find-my-way options as a second argument:

const router = createRouter(finalHandler, {
  caseSensitive: false,
  ignoreTrailingSlash: true
})

Declaring routes

Use HTTP verb methods to define your routes:

router
  .get('/', (req, res) => res.end('Hello World'))
  .post('/users', (req, res) => res.end('User created'))
  .put('/users/:id', (req, res) => res.end('User updated'))
  .delete('/users/:id', (req, res) => res.end('User deleted'))

Use .all() to match any HTTP method:

router.all('/ping', (req, res) => res.end('pong'))

The dynamic segments will be captured using the :param syntax, with parameters accessible via req.params:

router.get('/users/:id', (req, res) => {
  res.end(`User ID: ${req.params.id}`)
})

router.get('/posts/:year/:month', (req, res) => {
  const { year, month } = req.params
  res.end(`Posts from ${month}/${year}`)
})

See Request object for details on how to access route parameters and other useful properties added to req.

Declaring middlewares

A middleware is declared using .use(). it will be added globally before running any route:

// Global middleware (runs on every request)
router
  .use((req, res, next) => {
    req.timestamp = Date.now()
    next()
})

You can also declare middleware specific to routes:

const auth = (req, res, next) => { /* verify token */ next() }
const log = (req, res, next) => { /* log request */ next() }

const protected = [auth, log]

router
  .get('/admin', protected, (req, res) => res.end('Admin panel'))
  .get('/settings', protected, (req, res) => res.end('Settings'))

If you want to add a middleware conditionally, just return a falsy value:

router
  .use(process.env.NODE_ENV === 'production' && rateLimiter())

Starting the server

The router is a standard request handler. Pass it to http.createServer:

const http = require('http')

console.log(router.prettyPrint())
// └── / (GET)
//     ├── favicon.ico (GET)
//     └── user/
//         └── :id (GET)

http.createServer(router).listen(3000)

Advanced

Request object

The router adds these properties to req:

| Property | Description | |----------|-------------| | req.path | URL pathname | | req.params | Route parameters object | | req.query | Raw query string (after ?) | | req.search | Raw search string (including ?) |

req.query and req.search are only set if not already present.

Print routes

You can visualize your router's routes in a readable tree format using the router.prettyPrint() method. This is especially helpful for debugging or understanding your route structure at a glance.

For example:

const http = require('http')

console.log(router.prettyPrint())
// └── / (GET)
//     ├── favicon.ico (GET)
//     └── user/
//         └── :id (GET)

http.createServer(router).listen(3000)

The printed output shows the nested structure of your routes along with their registered HTTP methods. This works for both flat and deeply nested routers, including those mounted via .use().

See more in find-my-way prettyPrint documentation.

Nested routers

You can use a router as a middleware for another router. This is useful for prefixing routes or for modularizing your application:

const createRouter = require('router-http')
const http = require('http')

const final = (err, req, res) => {
  res.statusCode = err ? 500 : 404
  res.end(err ? err.message : 'Not Found')
}

// 1. Create a sub-router for API v1
const v1 = createRouter(final)
v1.get('/info', (req, res) => res.end('v1 info'))

// 2. Create another sub-router for API v2
const v2 = createRouter(final)
v2.get('/info', (req, res) => res.end('v2 info'))

// 3. Create the main router and mount sub-routers
const router = createRouter(final)

router
  .use('/v1', v1)
  .use('/v2', v2)
  .get('/', (req, res) => res.end('Welcome to the main router'))

http.createServer(router).listen(3000)

When a sub-router is used as a middleware, it will only handle requests that match its prefix. If no route matches inside the sub-router, it will automatically call next() to pass control back to the parent router.

Skipping to parent router

Use next('router') to exit the current router and pass control back to the parent:

const beta = createRouter(finalHandler)

beta.use((req, res, next) => {
  if (!req.isBetaTester) return next('router')
  next()
})

beta.get('/feature', (req, res) => res.end('Beta feature'))

router.use('/v1', beta)
router.get('/v1/feature', (req, res) => res.end('Stable feature'))

Benchmark

With all the improvements, router-http is approximately 30% faster than the express router:

[email protected]

Running 30s test @ http://localhost:3000/user/123
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.23ms    1.40ms  96.27ms   99.61%
    Req/Sec    10.15k   615.89    11.07k    86.24%
  2430687 requests in 30.10s, 356.98MB read
Requests/sec:  80752.48
Transfer/sec:     11.86MB

router-http

Running 30s test @ http://localhost:3000/user/123
  8 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.97ms    1.27ms  84.82ms   99.77%
    Req/Sec    12.91k     1.07k   14.67k    71.51%
  3092927 requests in 30.10s, 386.40MB read
Requests/sec: 102751.65
Transfer/sec:     12.84MB

See benchmark for details.

Related

License

router-http © Kiko Beats, released under the MIT License.

Credits to Luke Edwards for Polka which inspired this project.