Declarative, asynchronous routing for React.

Navi is a JavaScript library for declaratively mapping URLs to asynchronous content. With Navi, you use simple functions, Promises and async/await to map your app’s URLs to data and views.

Navi comes with a set of modern React components that take advantage of Suspense and Hooks. And as icing on the cake, Navi is designed to make pre-rendering for SEO a breeze — it even lets you statically render your app without ejecting from create-react-app!

Try Navi.

Navi is just a library, and so it works great with both new and existing apps.

npm install navi react-navi

The quickest way to try Navi is to play with the embedded editor below. It demonstrates how to implement a simple site selling hats and flamethrowers, including the basics of routing, linking, code splitting, and SEO.

To quickly try Navi in a new project, you can start with a create-react-app based template:

  • create-react-navi-app
    Creates a project skeleton using create-react-app, then adds a couple apps and static rendering.

  • create-react-blog
    Creates a project skeleton using create-react-app, then adds routes generated from your filesystem structure, static rendering, pagination, tags, MDX, an RSS feed, a Netlify deploy script, and a theme inspired by Dan Abramov’s, for a ready-to-go blog.

Or if you’d like to see how simple it is to add Navi to your own create-react-app project, head on over to Getting Started guide.

Oh, and if you already have an app built with react-router? Then adding Navi is ridiculously easy — just mount your Navi routes within a react-router <Route>. For details, see the guide to integrating with react-router.

Try a live example.

import { mount, route, lazy } from 'navi'
import React, { Suspense } from 'react'
import ReactDOM from 'react-dom'
import { Router, View } from 'react-navi'
import api from './api'
import Landing from './Landing'
import Layout from './Layout'

// Define routes using mount(), route(), and other middleware.
const routes =
    '/': route({
      title: "Hats 'n' Flamethrowers 'r' Us",
      getData: () => api.fetchProducts(),
      view: <Landing />,
    '/product': lazy(() => import('./product')),

// Then pass your routes to a `<Router>`, and render them with `<View>`.
  <Router routes={routes}>
      <Suspense fallback={null}>
        <View />
Build In Progress

Jump to…