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. For more information, see benchmarks.

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

Installation

To start using the router, simply install into an existing Raptor application via the CLI or, if you are using Deno, import it directly from JSR.

deno add jsr:@raptor/router
bunx jsr add @raptor/router
npx jsr add @raptor/router
yarn dlx jsr add @raptor/router
pnpm dlx jsr add @raptor/router

Type inference

To get full type inference with @raptor/router, you'll need to add type declarations to your project. This is a one-time setup that enables type-safe validation throughout your entire codebase.

Why is this needed?

JSR (JavaScript Registry) doesn't allow packages to modify global types directly. Since the validator extends the native Request object with a params property, we need to declare this package in your project.

The good news: Once configured, you get full autocomplete and type safety everywhere you use context.request.params.

Setup

In the root of your project (or in your src/ directory), create a file named types.d.ts:

// types.d.ts
import type { Params } from "@raptor/router";
 
declare global {
  interface Request {
    params: Params;
  }
}
 
export {};

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

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

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

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

import { Router, Route } from "@raptor/router";
import { Kernel, Context, HttpMethod } from "@raptor/kernel";
 
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();

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.

import { Route } from "@raptor/router";
import { type Context, HttpMethod } from "@raptor/kernel";
 
/* ... */
 
const route = new Route({
  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 { Route } from "@raptor/router";
import { type Context, Forbidden, HttpMethod } from "@raptor/kernel";
 
/* ... */
 
const authMiddleware = (context: Context, next: CallableFunction) => {
  const customHeader = context.request.headers.get("X-Header");
 
  if (!customerHeader) {
    throw new Forbidden();
  }
 
  return next();
};
 
const route = new 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 = new RouteGroup({
  name: "api.",
  prefix: "/api"          
});
 
// Define our routes for the API.
const routes = [
  new Route({
    name: "user.index",
    pathname: "/users",
    method: HttpMethod.GET,
    handler: () => "OK"
  })
];
 
// Add our routes to the group.
group.add(routes);
 
// 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 = new RouteGroup({
  name: "api.",
  prefix: "/api",
  middleware: (context: Context, next: CallableFunction) => {
    console.log("Running the route group middleware.");
 
    return next();
  }       
});
© 2026 Raptor