Core Concepts

Routing

A guide to routing in Raptor

Introduction

Fast, predictable HTTP routing with sub-2 micro-second performance. Supports parameters, wildcards, and multiple HTTP methods with consistent speed from 10 to 500+ routes. No edge cases. No performance degradation. Just reliable routing that scales.

Benchmarking

Benchmarks are benchmarks, they are only here for your reference. All benchmarks have been run on a full application bootstrap, using an Apple M3 Pro @ 3.5GHz with Mitata for accurate microsecond-level measurements.

BenchmarkBun 1.3.5Node 22.19Deno 2.6.3
Static routes (100)1.36 µs3.14 µs2.69 µs
Dynamic routes (100)1.42 µs3.09 µs2.44 µs
Mixed routes (70/30)1.37 µs2.87 µs2.29 µs
Worst case (last of 100)1.45 µs3.10 µs2.40 µs
Large router (500 routes)1.43 µs2.96 µs2.30 µs

Installation

To start using the router, simply install into an existing Raptor application with your package manager.

deno add npm:@raptor-js/router
bun add @raptor-js/router
npm install @raptor-js/router
yarn add @raptor-js/router
pnpm add @raptor-js/router

Type inference

The package adds params to the global Request type for you, so you get autocomplete and type safety as soon as you import it.

Configuration

An optional configuration object is available, allowing you to customise your router setup.

import { HttpMethod } from "@raptor-js/types";
import type { Config } from "@raptor-js/router";
 
export default {
  /**
   * Whether the router should throw a 404 Not Found error when no route
   * matches the incoming request. When false, the request is passed to
   * the next middleware instead.
   */
  throwNotFound: false,
 
  /**
   * The routes and route groups available to the application.
   */
  routes: [
    {
      method: HttpMethod.GET,
      pathname: "/hello",
      handler: () => "Hello, World!",
    },
  ],
} satisfies Config;

For more information about the config-driven setup, see Configuration.

Usage

The built-in router operates similarly to standard Raptor middleware, enabling you to define routes using familiar parameter patterns such as /users/:id.

Adding routes to the router

Configuration

Using configuration, you can easily add routes to your application as follows:

import { Kernel } from "@raptor-js/kernel";
import router, { Route } from "@raptor-js/router";
import { type Context, HttpMethod } from "@raptor-js/types";
 
const app = new Kernel();
 
app.use(
  router({
    routes: [
      {
        name: "index",
        method: HttpMethod.GET,
        pathname: "/",
        handler: () => "Hello, Dr Malcolm!",
      },
    ],
  }),
);
 
app.serve();

Instance methods

If you prefer, you can also instantiate the router yourself and add routes with the instance methods:

import { Kernel } from "@raptor-js/kernel";
import { Router, Route } from "@raptor-js/router";
import { type Context, HttpMethod } from "@raptor-js/types";
 
const app = new Kernel();
 
const router = new Router();
 
router.add([
  new Route({
    name: "index",
    method: HttpMethod.GET,
    pathname: "/",
    handler: () => "Hello, Dr Malcolm!",
  }),
]);
 
app.use(router.handle);
 
app.serve();

Ergonomic methods

Or finally, ergonomic methods are available within the router (recommended only for smaller applications);

import { Kernel } from "@raptor-js/kernel";
import { Router, Route } from "@raptor-js/router";
import { type Context, HttpMethod } from "@raptor-js/types";
 
const app = new Kernel();
 
const router = new Router();
 
router.get("/", () => "Hello, Dr Malcolm!", { name: "index" });
 
app.use(router.handle);
 
app.serve();

Route Parameters

Route parameter values are processed and available via the router's context object context.request.params if they are found in the route's pathname. Make sure to add the types.d.ts definitions from above.

{
  name: "person.read",
  method: HttpMethod.GET,
  pathname: "/person/:name";
  handler: (context: Context) => {
    const { name } = context.request.params;
 
    return `Hello ${name}`;
  }
}

Route Middleware

Middleware can be added to individual routes by using the optional middleware property.

import type { Context, Next } from "@raptor-js/types";
import { Forbidden, HttpMethod } from "@raptor-js/kernel";
 
/* ... */
 
const authMiddleware = (context: Context, next: Next) => {
  const customHeader = context.request.headers.get("X-Header");
 
  if (!customerHeader) {
    throw new Forbidden();
  }
 
  return next();
};
 
const route = {
  name: "user.index",
  method: HttpMethod.GET,
  pathname: "/users";
  middleware: authMiddleware,
  handler: () => "Hello, Dr Malcom!"
};
 
/* ... */

The following code will check for the custom header's existence before continuing to the handler.

Multiple middleware

Multiple middleware functions can be added as an array. The system will run through each before finally moving on to the defined handler function. For more information, see Middleware.

Route Groups

Route Groups are a convenient and easy way to share functionality across multiple routes. You can configure prefixes and add middleware to multiple routes. You can add groups in exactly the same way you add routes to the router, with the add() method.

Prefixes

If you need to share a common prefix across multiple routes, you can add a name and path prefix to a Route Group.

// Setup a new group for our API routes.
const group = {
  name: "api.",
  prefix: "/api",
  routes: [
    {
      name: "user.index",
      pathname: "/users",
      method: HttpMethod.GET,
      handler: () => "OK",
    },
  ],
};
 
// Add the group to the router.
router.add(group);

Middleware

If you want to share common middleware across multiple routes, you can add one or more to a group in exactly the same way as you can with a normal route. The middleware property accepts a Middleware instance or an array.

// Add a middleware to all of our API routes.
const group = {
  name: "api.",
  prefix: "/api",
  middleware: (context: Context, next: Next) => {
    console.log("Running the route group middleware.");
 
    return next();
  },
};
© 2026 Raptor