Routing Manually

Mapping URL Patterns to Handlers — Without a Framework

Routing Manually

Match method + path to a handler. Build it once to see what frameworks do for you.

4 min read Level 2/5 #nodejs#http#routing
What you'll learn
  • Match method + path patterns
  • Extract path params and query strings
  • Wire a tiny router

node:http gives you raw req.url and req.method. To handle multiple routes, you build (or use) a router. Here’s the hand-rolled version — useful to see what frameworks abstract.

A Tiny Router

import { createServer } from "node:http";

const routes = [
  { method: "GET",    pattern: /^\/$/,             handler: home },
  { method: "GET",    pattern: /^\/users$/,        handler: listUsers },
  { method: "GET",    pattern: /^\/users\/(\d+)$/, handler: getUser },
  { method: "POST",   pattern: /^\/users$/,        handler: createUser },
];

createServer(async (req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);

  for (const route of routes) {
    if (route.method !== req.method) continue;
    const match = url.pathname.match(route.pattern);
    if (match) {
      return route.handler(req, res, match.slice(1));
    }
  }
  res.statusCode = 404;
  res.end("not found");
}).listen(3000);

function home(req, res) {
  res.end("hello");
}
function listUsers(req, res) {
  res.setHeader("content-type", "application/json");
  res.end(JSON.stringify([{ id: 1 }, { id: 2 }]));
}
function getUser(req, res, [id]) {
  res.setHeader("content-type", "application/json");
  res.end(JSON.stringify({ id: Number(id) }));
}
async function createUser(req, res) {
  res.statusCode = 201;
  res.end("created");
}

Pattern-match the URL, dispatch to a handler, pass path params.

Query Strings

const url = new URL(req.url, `http://${req.headers.host}`);
const limit = url.searchParams.get("limit") ?? "10";
const tags  = url.searchParams.getAll("tag");

URLSearchParams is the standard API — same in browsers.

Why This Gets Old

Real routers handle:

  • Globs (/posts/*)
  • Optional params (/users/:id?)
  • Wildcards (/api/*splat)
  • Method-specific 405 vs 404
  • Middleware chains

Reinventing these correctly is a weekend project. Use Express, Fastify, or any router lib (like find-my-way if you want a tiny one).

Up Next

The fetch API — same in Node and the browser, for making outbound HTTP calls.

fetch in Node →