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

@jsonjoy.com/jit-router

v18.15.0

Published

High-performance HTTP router with JIT compilation.

Readme

json-joy JIT Router

A high-performance HTTP router that constructs a hybrid Trie and Radix tree of the route structure and then JIT compiles the routes into a single optimized function for maximum performance.

Key Features

  • Ultra-Fast Performance: JIT compilation generates optimized JavaScript functions for route matching
  • Hybrid Tree Structure: Combines Trie and Radix tree algorithms for efficient path matching
  • Flexible Route Patterns: Supports exact matches, parameters, wildcards, and regex patterns
  • Parameter Extraction: Automatically extracts and validates route parameters
  • TypeScript Support: Full TypeScript definitions with generic data types
  • Zero Dependencies: Core runtime has no external dependencies for maximum efficiency

Installation

npm install @jsonjoy.com/jit-router

Quick Start

import { Router } from '@jsonjoy.com/jit-router';

// Create a new router instance
const router = new Router();

// Add routes with associated data
router.add('GET /users', { handler: 'listUsers' });
router.add('GET /users/{id}', { handler: 'getUser' });
router.add('POST /users/{id}/posts', { handler: 'createPost' });

// Compile routes into an optimized matcher function
const matcher = router.compile();

// Match incoming requests
const match = matcher('GET /users/123');
if (match) {
  console.log(match.data);    // { handler: 'getUser' }
  console.log(match.params);  // ['123']
}

Destinations

Destinations are the core concept in jit-router. Each destination represents an endpoint with associated data and can be reached via one or more route patterns.

Creating Destinations

// Single route destination
router.add('GET /ping', 'PING_HANDLER');

// Multiple routes leading to same destination
router.add(['GET /ping', 'GET /pong'], 'PING_HANDLER');

// With custom data
router.add('GET /users/{id}', { 
  handler: getUserHandler,
  middleware: [authMiddleware],
  cache: true 
});

Destination Properties

Each destination contains:

  • routes: Array of route patterns that lead to this destination
  • data: Associated data (handler, metadata, etc.)
  • match: Match object returned when route is matched

Route Patterns and Step Specifications

Routes consist of steps that define the matching pattern. There are three types of steps:

1. Exact Steps

Match literal text exactly:

router.add('GET /api/users', 'USERS_API');
router.add('POST /login', 'LOGIN');

2. Parameter Steps (Until Steps)

Extract parameters from the URL path:

// Basic parameter - matches until next '/'
router.add('GET /users/{id}', 'GET_USER');

// Custom delimiter - matches until specified character
router.add('GET /files/{name}.{ext}', 'GET_FILE');

// Wildcard - matches until end of string
router.add('GET /static/{path::\n}', 'STATIC_FILES');

Parameter Syntax:

  • {name} - matches until next / (default delimiter)
  • {name::delimiter} - matches until specified delimiter
  • {name::\n} - matches until end of string (wildcard)

3. Regex Steps

Match parameters with regex patterns:

// HTTP method matching
router.add('{method:(GET|POST)} /api/{endpoint}', 'API_HANDLER');

// Numeric IDs only
router.add('GET /users/{id:[0-9]+}', 'GET_USER_BY_ID');

// Optional path segments
router.add('GET /posts{slug:(/[^/]+)?}', 'GET_POST');

// Complex patterns
router.add('{method:[A-Z]+} /rpc/{procedure}', 'RPC_HANDLER');

Regex Syntax:

  • {name:pattern} - matches with regex pattern
  • {name:pattern:delimiter} - regex pattern with custom delimiter

Parameter Extraction

Parameters are automatically extracted and provided in the match result:

const router = new Router();
router.add('GET /users/{userId}/posts/{postId}', 'GET_USER_POST');
const matcher = router.compile();

const match = matcher('GET /users/123/posts/456');
// match.params = ['123', '456']

// Parameters correspond to the order they appear in the route
const [userId, postId] = match.params;

Named Parameter Access

For better parameter handling, consider structuring your data to include parameter names:

router.add('GET /users/{userId}/posts/{postId}', {
  handler: 'getUserPost',
  params: ['userId', 'postId']
});

const match = matcher('GET /users/123/posts/456');
if (match) {
  const params = {};
  match.data.params.forEach((name, index) => {
    params[name] = match.params[index];
  });
  // params = { userId: '123', postId: '456' }
}

Code Generation and Compilation

The router uses JIT (Just-In-Time) compilation to generate highly optimized JavaScript functions:

Compilation Process

  1. Tree Construction: Routes are organized into a hybrid Trie/Radix tree structure
  2. Code Generation: The tree is traversed to generate optimized JavaScript code
  3. Function Creation: Code is compiled into a fast matcher function
const router = new Router();
router.add('GET /users/{id}', 'USER_HANDLER');

// View the internal tree structure
console.log(router.toString());

// Compile to optimized function
const matcher = router.compile();

// View generated code (for debugging)
console.log(matcher.toString());

Performance Characteristics

The JIT compilation produces functions with these optimizations:

  • No loops: Uses conditional branches instead of iteration
  • String operations: Optimized string slicing and comparison
  • Early returns: Matches return immediately when found
  • Minimal allocations: Reuses objects and avoids unnecessary memory allocation

Advanced Usage Examples

Complex Routing Patterns

const router = new Router();

// API versioning
router.add('GET /api/v{version:[12]}/users', 'API_USERS');

// File serving with extensions
router.add('GET /assets/{file}.{ext:(js|css|png|jpg)}', 'STATIC_ASSET');

// Optional trailing slashes
router.add('GET /blog{trailing:/?}', 'BLOG_INDEX');

// Nested parameters with validation
router.add('POST /orgs/{org}/repos/{repo}/issues/{num:[0-9]+}', 'GITHUB_ISSUE');

// Wildcard with method matching
router.add('{method:(GET|HEAD)} /files/{path::\n}', 'FILE_HANDLER');

const matcher = router.compile();

Custom Router Options

// Custom default delimiter
const router = new Router({ 
  defaultUntil: '|'  // Use '|' instead of '/' as default delimiter
});

router.add('GET |users|{id}', 'USER_HANDLER');

Type-Safe Usage with TypeScript

interface RouteData {
  handler: string;
  middleware?: Function[];
  cache?: boolean;
}

const router = new Router<RouteData>();

router.add('GET /users/{id}', {
  handler: 'getUser',
  middleware: [authMiddleware],
  cache: true
});

const matcher = router.compile();
const match = matcher('GET /users/123');

if (match) {
  // TypeScript knows match.data is RouteData
  console.log(match.data.handler);     // 'getUser'
  console.log(match.data.cache);       // true
  console.log(match.params);           // ['123']
}

Route Introspection

const router = new Router();
router.add('GET /users/{id}', 'USER_HANDLER');
router.add('POST /users', 'CREATE_USER');

// Inspect destinations
console.log('Destinations:', router.destinations.length);
router.destinations.forEach((dest, i) => {
  console.log(`[${i}]:`, dest.routes.map(r => r.toText()));
});

// View routing tree structure
const tree = router.tree();
console.log(tree.toString('  '));

API Reference

Router Class

Constructor

new Router<Data>(options?: RouterOptions)

Options:

  • defaultUntil?: string - Default delimiter for parameter steps (default: '/')

Methods

add(route: string | string[], data: Data): void

Add a route or multiple routes to the same destination.

addDestination(destination: Destination): void

Add a pre-constructed destination.

compile(): RouteMatcher<Data>

Compile routes into an optimized matcher function.

tree(): RoutingTreeNode

Get the internal routing tree structure.

RouteMatcher Function

(route: string) => Match<Data> | undefined

Returns a Match object if the route matches, undefined otherwise.

Match Object

interface Match<Data> {
  data: Data;           // Associated route data
  params: string[];     // Extracted parameters
}

Route Step Types

ExactStep

Matches literal text exactly.

UntilStep

Matches parameters until a delimiter:

  • name: string - Parameter name
  • until: string - Delimiter character

RegexStep

Matches parameters with regex patterns:

  • name: string - Parameter name
  • regex: string - Regex pattern
  • until: string - Delimiter character

Error Handling

The router handles various edge cases gracefully:

const router = new Router();
router.add('GET /users/{id}', 'USER_HANDLER');
const matcher = router.compile();

// Non-matching routes return undefined
console.log(matcher('GET /posts/123'));     // undefined
console.log(matcher('POST /users/123'));    // undefined

// Empty or invalid routes return undefined  
console.log(matcher(''));                   // undefined
console.log(matcher('INVALID'));           // undefined

Benchmarks

Comparing json-joy against the second fastest router find-my-way (used in Fastify):

npx ts-node src/__bench__/realistic.bench.ts

Results:

json-joy router x 1,799,920 ops/sec ±0.74% (99 runs sampled), 556 ns/op
find-my-way x 389,132 ops/sec ±4.60% (87 runs sampled), 2570 ns/op
json-joy router: GET /ping x 151,628,101 ops/sec ±1.83% (87 runs sampled), 7 ns/op
find-my-way: GET /ping x 14,820,512 ops/sec ±0.23% (100 runs sampled), 67 ns/op
json-joy router: GET /pong x 103,442,010 ops/sec ±0.49% (101 runs sampled), 10 ns/op
find-my-way: GET /pong x 12,396,065 ops/sec ±0.14% (95 runs sampled), 81 ns/op
json-joy router: POST /ping x 155,689,270 ops/sec ±0.26% (96 runs sampled), 6 ns/op
find-my-way: POST /ping x 14,964,742 ops/sec ±0.62% (100 runs sampled), 67 ns/op
json-joy router: POST /echo x 103,757,580 ops/sec ±0.24% (94 runs sampled), 10 ns/op
find-my-way: POST /echo x 19,484,996 ops/sec ±0.13% (100 runs sampled), 51 ns/op
json-joy router: GET /info x 86,407,568 ops/sec ±0.45% (101 runs sampled), 12 ns/op
find-my-way: GET /info x 19,090,564 ops/sec ±0.23% (99 runs sampled), 52 ns/op
json-joy router: GET /types x 82,040,568 ops/sec ±0.19% (93 runs sampled), 12 ns/op
find-my-way: GET /types x 18,258,167 ops/sec ±0.13% (94 runs sampled), 55 ns/op
json-joy router: PUT /events x 155,566,843 ops/sec ±0.30% (95 runs sampled), 6 ns/op
find-my-way: PUT /events x 17,947,965 ops/sec ±0.29% (95 runs sampled), 56 ns/op
json-joy router: GET /users x 67,873,498 ops/sec ±0.19% (97 runs sampled), 15 ns/op
find-my-way: GET /users x 18,427,182 ops/sec ±0.70% (97 runs sampled), 54 ns/op
json-joy router: GET /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx x 24,268,077 ops/sec ±0.38% (98 runs sampled), 41 ns/op
find-my-way: GET /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx x 5,830,219 ops/sec ±0.20% (101 runs sampled), 172 ns/op
json-joy router: GET /users/123 x 23,750,636 ops/sec ±0.92% (98 runs sampled), 42 ns/op
find-my-way: GET /users/123 x 8,883,381 ops/sec ±0.15% (98 runs sampled), 113 ns/op
json-joy router: DELETE /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx x 21,578,200 ops/sec ±0.98% (96 runs sampled), 46 ns/op
find-my-way: DELETE /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx x 6,081,393 ops/sec ±0.82% (96 runs sampled), 164 ns/op
json-joy router: POST /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx x 19,981,015 ops/sec ±0.16% (96 runs sampled), 50 ns/op
find-my-way: POST /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx x 6,094,531 ops/sec ±0.27% (96 runs sampled), 164 ns/op
json-joy router: GET /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers x 17,566,830 ops/sec ±0.92% (99 runs sampled), 57 ns/op
find-my-way: GET /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers x 4,584,840 ops/sec ±0.27% (97 runs sampled), 218 ns/op
json-joy router: GET /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy x 13,432,092 ops/sec ±0.26% (100 runs sampled), 74 ns/op
find-my-way: GET /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy x 2,959,002 ops/sec ±0.17% (100 runs sampled), 338 ns/op
json-joy router: POST /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy x 12,074,790 ops/sec ±1.05% (98 runs sampled), 83 ns/op
find-my-way: POST /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy x 3,211,678 ops/sec ±0.31% (96 runs sampled), 311 ns/op
json-joy router: DELETE /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy x 12,878,647 ops/sec ±0.30% (99 runs sampled), 78 ns/op
find-my-way: DELETE /users/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/followers/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy x 3,214,022 ops/sec ±0.69% (95 runs sampled), 311 ns/op
json-joy router: GET /posts x 47,369,117 ops/sec ±1.64% (83 runs sampled), 21 ns/op
find-my-way: GET /posts x 11,424,540 ops/sec ±0.17% (101 runs sampled), 88 ns/op
json-joy router: GET /posts/search x 91,571,586 ops/sec ±1.22% (94 runs sampled), 11 ns/op
find-my-way: GET /posts/search x 6,931,399 ops/sec ±0.16% (100 runs sampled), 144 ns/op
json-joy router: POST /posts x 71,501,062 ops/sec ±0.91% (93 runs sampled), 14 ns/op
find-my-way: POST /posts x 13,755,641 ops/sec ±0.21% (98 runs sampled), 73 ns/op
json-joy router: GET /posts/jhasdf982lsd x 20,794,603 ops/sec ±0.79% (97 runs sampled), 48 ns/op
find-my-way: GET /posts/jhasdf982lsd x 6,220,203 ops/sec ±0.17% (100 runs sampled), 161 ns/op
json-joy router: POST /posts/jhasdf982lsd x 17,002,131 ops/sec ±0.24% (94 runs sampled), 59 ns/op
find-my-way: POST /posts/jhasdf982lsd x 6,783,108 ops/sec ±0.64% (98 runs sampled), 147 ns/op
json-joy router: DELETE /posts/jhasdf982lsd x 18,912,944 ops/sec ±0.38% (95 runs sampled), 53 ns/op
find-my-way: DELETE /posts/jhasdf982lsd x 8,353,962 ops/sec ±0.84% (99 runs sampled), 120 ns/op
json-joy router: GET /posts/jhasdf982lsd/tags x 16,857,334 ops/sec ±4.01% (92 runs sampled), 59 ns/op
find-my-way: GET /posts/jhasdf982lsd/tags x 5,169,375 ops/sec ±0.39% (98 runs sampled), 193 ns/op
json-joy router: GET /posts/jhasdf982lsd/tags/top x 16,012,780 ops/sec ±0.38% (99 runs sampled), 62 ns/op
find-my-way: GET /posts/jhasdf982lsd/tags/top x 4,062,952 ops/sec ±0.65% (97 runs sampled), 246 ns/op
json-joy router: GET /posts/jhasdf982lsd/tags/123 x 12,144,904 ops/sec ±0.21% (100 runs sampled), 82 ns/op
find-my-way: GET /posts/jhasdf982lsd/tags/123 x 4,036,060 ops/sec ±0.15% (98 runs sampled), 248 ns/op
json-joy router: DELETE /posts/jhasdf982lsd/tags/123 x 11,797,726 ops/sec ±0.50% (94 runs sampled), 85 ns/op
find-my-way: DELETE /posts/jhasdf982lsd/tags/123 x 5,269,916 ops/sec ±0.10% (100 runs sampled), 190 ns/op
json-joy router: POST /posts/jhasdf982lsd/tags x 15,483,784 ops/sec ±0.20% (100 runs sampled), 65 ns/op
find-my-way: POST /posts/jhasdf982lsd/tags x 5,586,607 ops/sec ±0.10% (100 runs sampled), 179 ns/op
json-joy router: GET /api/collections x 89,443,474 ops/sec ±1.14% (93 runs sampled), 11 ns/op
find-my-way: GET /api/collections x 11,365,669 ops/sec ±0.15% (102 runs sampled), 88 ns/op
json-joy router: POST /api/collections x 88,558,408 ops/sec ±1.15% (93 runs sampled), 11 ns/op
find-my-way: POST /api/collections x 11,427,491 ops/sec ±0.14% (98 runs sampled), 88 ns/op
json-joy router: GET /api/collections/123 x 15,327,034 ops/sec ±0.21% (101 runs sampled), 65 ns/op
find-my-way: GET /api/collections/123 x 6,654,562 ops/sec ±0.10% (102 runs sampled), 150 ns/op
json-joy router: PUT /api/collections/123 x 14,766,966 ops/sec ±0.23% (100 runs sampled), 68 ns/op
find-my-way: PUT /api/collections/123 x 7,446,186 ops/sec ±0.14% (99 runs sampled), 134 ns/op
json-joy router: POST /api/collections/123 x 13,397,211 ops/sec ±0.23% (100 runs sampled), 75 ns/op
find-my-way: POST /api/collections/123 x 5,801,550 ops/sec ±6.34% (92 runs sampled), 172 ns/op
json-joy router: DELETE /api/collections/123 x 16,470,990 ops/sec ±0.26% (99 runs sampled), 61 ns/op
find-my-way: DELETE /api/collections/123 x 6,618,101 ops/sec ±4.54% (90 runs sampled), 151 ns/op
json-joy router: GET /api/collections/123/documents x 10,819,176 ops/sec ±20.48% (90 runs sampled), 92 ns/op
find-my-way: GET /api/collections/123/documents x 5,083,007 ops/sec ±0.10% (100 runs sampled), 197 ns/op
json-joy router: POST /api/collections/123/documents x 11,471,312 ops/sec ±0.18% (101 runs sampled), 87 ns/op
find-my-way: POST /api/collections/123/documents x 5,024,672 ops/sec ±0.14% (97 runs sampled), 199 ns/op
json-joy router: GET /api/collections/123/documents/456 x 8,776,775 ops/sec ±0.25% (98 runs sampled), 114 ns/op
find-my-way: GET /api/collections/123/documents/456 x 3,892,995 ops/sec ±0.30% (100 runs sampled), 257 ns/op
json-joy router: PUT /api/collections/123/documents/456 x 9,946,515 ops/sec ±1.36% (97 runs sampled), 101 ns/op
find-my-way: PUT /api/collections/123/documents/456 x 4,347,762 ops/sec ±0.62% (98 runs sampled), 230 ns/op
json-joy router: POST /api/collections/123/documents/456 x 8,120,919 ops/sec ±0.44% (99 runs sampled), 123 ns/op
find-my-way: POST /api/collections/123/documents/456 x 3,882,741 ops/sec ±1.26% (92 runs sampled), 258 ns/op
json-joy router: DELETE /api/collections/123/documents/456 x 10,739,860 ops/sec ±0.89% (97 runs sampled), 93 ns/op
find-my-way: DELETE /api/collections/123/documents/456 x 4,483,659 ops/sec ±1.17% (98 runs sampled), 223 ns/op
json-joy router: GET /api/collections/123/documents/456/revisions x 8,553,359 ops/sec ±0.91% (98 runs sampled), 117 ns/op
find-my-way: GET /api/collections/123/documents/456/revisions x 3,379,187 ops/sec ±0.17% (101 runs sampled), 296 ns/op
json-joy router: GET /api/collections/123/documents/456/revisions/find x 8,092,442 ops/sec ±1.10% (97 runs sampled), 124 ns/op
find-my-way: GET /api/collections/123/documents/456/revisions/find x 2,829,474 ops/sec ±0.17% (100 runs sampled), 353 ns/op
json-joy router: POST /api/collections/123/documents/456/revisions x 7,750,406 ops/sec ±0.93% (99 runs sampled), 129 ns/op
find-my-way: POST /api/collections/123/documents/456/revisions x 3,412,482 ops/sec ±0.14% (98 runs sampled), 293 ns/op
json-joy router: GET /api/collections/123/documents/456/revisions/789 x 7,133,453 ops/sec ±0.51% (98 runs sampled), 140 ns/op
find-my-way: GET /api/collections/123/documents/456/revisions/789 x 2,851,795 ops/sec ±0.80% (95 runs sampled), 351 ns/op
json-joy router: DELETE /api/collections/123/documents/456/revisions/789 x 8,168,205 ops/sec ±0.24% (96 runs sampled), 122 ns/op
find-my-way: DELETE /api/collections/123/documents/456/revisions/789 x 3,282,963 ops/sec ±0.10% (98 runs sampled), 305 ns/op
json-joy router: GET /files/user123-movies/2019/01/01/1.mp4 x 13,990,918 ops/sec ±0.19% (100 runs sampled), 71 ns/op
find-my-way: GET /files/user123-movies/2019/01/01/1.mp4 x 5,132,706 ops/sec ±0.90% (101 runs sampled), 195 ns/op
json-joy router: PUT /files/user123-movies/2019/01/01/1.mp4 x 13,951,426 ops/sec ±0.23% (99 runs sampled), 72 ns/op
find-my-way: PUT /files/user123-movies/2019/01/01/1.mp4 x 5,184,318 ops/sec ±0.23% (99 runs sampled), 193 ns/op
json-joy router: GET /static/some/path/to/file.txt x 15,788,214 ops/sec ±1.06% (99 runs sampled), 63 ns/op
find-my-way: GET /static/some/path/to/file.txt x 8,104,177 ops/sec ±0.14% (100 runs sampled), 123 ns/op
Fastest is json-joy router: POST /ping,json-joy router: PUT /events,json-joy router: GET /ping