The @curi/router package is used to create a router.


If you have Node and NPM installed, you can install the package through npm (or yarn if you prefer).

npm install @curi/router
yarn add @curi/router

Prefer inline scripts? Every version is available through Unpkg.

There are both full and minified versions available.

You can access the package via window.Curi.

<script src="https://unpkg.com/@curi/router@1.0.0-beta.37/dist/curi-router.js"></script>



The curi export is a function to create a router. It has two required arguments: a history object and a routes array, and an optional third argument: an options object.

import { curi } from '@curi/router';

const router = curi(history, routes, options);



A Hickory history object that will power navigation within the application. The Getting Started guide provides more information on how to choose which history type is right for an application.

import Browser from "@hickory/browser";

const history = Browser();
const router = curi(history, routes);

An array of route objects for all valid routes in the application.

const routes = [
  { name: "Home", path: "" },
  { name: "About", path: "about" }

const router = curi(history, routes);

An optional object with additional properties that can be passed to the router.

  • route - An array of route interactions. These are functions for interacting with routes based on their name.

    The pathname interaction is included by default; any other interactions are provided through this array.

    import active from "@curi/route-active";
    import ancestors from "@curi/route-ancestors";
    const routes = [{ name: "Home", path: "" }];
    const router = curi(history, routes, {
      route: [active(), ancestors()]

    Route interactions are called via the router's route object.

    // returns true when location.pathname = "/"
    // returns "/"
  • sideEffects - An array of side effect objects.

    effectAn observer that will be called whenever a response is generated.
    after(default false) controls whether the side effect is called before or after non-side effect observers.
    import scroll from "@curi/side-effect-scroll";
    const router = curi(history, routes, {
      sideEffects: [scroll()]
  • emitRedirects - When false (default is true), response objects with the redirectTo property will not be emitted to observers. This can be useful for avoiding an extra render, but should not be used on the server.

    const routes = [
        name: "Old",
        path: "old/:id",
        response({ params }) {
          // setup a redirect to the "New" route
          return {
            redirectTo: {
              name: "New",
        name: "New",
        path: "new/:id"
    const router = curi(history, routes, {
      emitRedirects: false                 
    // navigating to "/old/2" will automatically redirect
    // to "/new/2" without emitting a response
  • pathnameOptions - Curi uses path-to-regexp to handle route matching and pathname generation. path-to-regexp can take a custom encode function for creating pathnames, which you can specify with this options. You most likely will never need to use this.

    const router = curi(history, routes, {
      pathOptions: {
        encode: (value, token) => { /* ... */ }

Router Properties#

The router has a number of properties for you to use when rendering your application.

respond(fn, options)#

The respond() method takes an observer function. Whenever a new response is made, the router will call that function. The function will be passed on object with three properties:

responseThe generated response object.
navigationThe navigation's action (PUSH, REPLACE, or POP) and the previous response object.
routerThe Curi router

When a matched route is async (it has an on.initial() or on.every() function), the router will not call the observer functions until the on function(s) have resolved.

router.respond(({ response }) => {
  // render the application based on the response
observefalseWhen true, the function will be called for all future responses that are emitted by the router (until it stops observing) When false, the function will only be called one time.
initialtrueWhen true, the function will be called immediately if a response exists. When false, the response function will not be called until the next response is emitted.
router.respond(responseHandler, {
                    observe: true

respond() returns a function to stop calling the observer function. This function is only returned when router.respond() is given the observe: true option.

const stopObserving = router.respond(
  () => {...},
  { observe: true }
// the router will now call the observer for all responses

// the router no longer calls the observer

The router.current() method returns the current response and navigation objects.

Note: If you call router.current() before the initial response has been emitted, the response and navigation properties will be null.
const router = curi(history, routes);
const tooSoon = router.current();
// tooSoon.response === null
// tooSoon.navigation === null

router.respond(({ response, navigation }) => {
  const perfect = router.current();
  // perfect.response === response
  // perfect.navigation === navigation

The router's route interactions are accessed through the route property. These are used to interact with routes using their names.


Curi includes one built-in interaction, pathname, which generates location pathnames using the name of a route and an optional object containing any necessary params.

const routes = [
  { name: 'User', path: 'user/:id' }
const router = curi(history, routes);
const userPathname = router.route.pathname(
  { id: '12345' }
// userPathname === '/user/12345'

The route's history object, in case you need to interact directly with that.


once takes a function as its argument and returns a new function. The first time the returned function is called, it will call the function passed to once(). Every call after that will re-use the result from the first call.

The once() function is useful for any async route match functions that only need to be called once.

Note: This will not work for functions whose result depends on variables that will change for a route (i.e. loading data based on route params).
import { once } from "@curi/router";
const routes = [
    name: "Menu",
    path: "menu",
    match: {
      // this function will be called every time the user
      // navigates to the "Menu" route
      nonCached: () => api.getItems(),
      // this function is only called the first time the
      // user navigates to the "Menu" route
      cached: once(() => api.getItems)


Curi automatically includes a pathname route interaction for you to generate URL pathnames for routes. If you need to access this same ability outside of a router, you can import the pathname route interaction.

import { pathname } from "@curi/router";

const pathnameGenerator = pathname();
// register routes
pathnameGenerator.register({ name: "Yo", path: "yo/:name" });
// generate pathname
const path = pathnameGenerator.get("Yo", { name: "joey" })
// path = "/yo/joey"