Skip to content

fetch-router Overview

The fetch-router package is the core routing engine of Remix. It takes an incoming HTTP request, figures out which code should handle it based on the URL and HTTP method, and returns a response. Everything is built on the Fetch API -- the same Request and Response types that browsers use -- so there are no framework-specific abstractions to learn.

What is Routing?

When someone visits a URL like /blog/my-first-post, your server needs to decide what to do with that request. Routing is the process of matching a URL to the right piece of code. A router is the tool that does this matching.

For example:

  • / should show the home page
  • /blog should list all blog posts
  • /blog/my-first-post should show a specific post
  • POST /contact should process a contact form submission

The router looks at both the URL path (like /blog/my-first-post) and the HTTP method (like GET or POST) to find the right handler.

Key Features

Type-Safe Routes

Define your routes as a structured object and get full TypeScript support throughout your application. Route parameters (the dynamic parts of a URL like :id or :slug) are automatically inferred so typos are caught at compile time, not in production.

ts
import { route } from 'remix/fetch-router/routes'

let routes = route({
  home: '/',
  posts: {
    index: '/posts',
    show: '/posts/:slug',
  },
})

// TypeScript knows `params.slug` is a string
router.get(routes.posts.show, ({ params }) => {
  return new Response(`Post: ${params.slug}`)
})

URL Generation with href()

Every route can generate its own URL. This means you never need to manually construct URL strings -- and if a route pattern changes, every generated link updates automatically.

ts
routes.posts.show.href({ slug: 'hello-world' })
// "/posts/hello-world"

Middleware

Middleware is code that runs before (or after) your route handler. It can inspect requests, add data to the request context, or short-circuit the response entirely. Middleware is useful for cross-cutting concerns like logging, authentication, and compression.

ts
import { createRouter } from 'remix/fetch-router'

let router = createRouter({
  middleware: [logger(), requireAuth()],
})

Controllers

Group related route handlers together using controllers. A controller maps a set of routes to their handlers, and TypeScript ensures every route has a handler and every handler receives the correct parameters.

ts
import type { Controller } from 'remix/fetch-router'

let postsController = {
  actions: {
    index() {
      return new Response('All posts')
    },
    show({ params }) {
      return new Response(`Post: ${params.slug}`)
    },
  },
} satisfies Controller<typeof routes.posts>

router.map(routes.posts, postsController)

Resource Routes

Generate all the standard CRUD routes for a resource with a single function call:

ts
import { route, resources } from 'remix/fetch-router/routes'

let routes = route({
  posts: resources('posts', { param: 'postId' }),
})
// Creates: index, new, create, show, edit, update, destroy

Quick Example

Here is a minimal Remix server with a few routes:

ts
import * as http from 'node:http'
import { createRouter } from 'remix/fetch-router'
import { route } from 'remix/fetch-router/routes'
import { createRequestListener } from 'remix/node-fetch-server'

// 1. Define routes
let routes = route({
  home: '/',
  greet: '/hello/:name',
})

// 2. Create a router
let router = createRouter()

// 3. Register handlers
router.get(routes.home, () => {
  return new Response('Welcome to Remix!')
})

router.get(routes.greet, ({ params }) => {
  return new Response(`Hello, ${params.name}!`)
})

// 4. Start the server
let server = http.createServer(createRequestListener(router.fetch))
server.listen(3000, () => {
  console.log('Listening on http://localhost:3000')
})

Visit http://localhost:3000/hello/world and you will see "Hello, world!".

How it Fits in the Remix Ecosystem

The fetch-router is the central piece that connects everything else:

  • route-pattern powers the URL matching engine under the hood.
  • node-fetch-server bridges the router to Node.js http.createServer().
  • fetch-proxy lets you forward requests to other servers from within route handlers.

Web Standards All the Way

Because Remix uses the standard Fetch API (Request, Response, Headers, URL), anything you learn here transfers directly to other platforms like Cloudflare Workers, Deno, and Bun. There is no lock-in to Node.js.

Next Steps

Released under the MIT License.