NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #2670 most downloaded on npm
Nested/Data-driven/Framework-agnostic Routing
Last release 1 months ago
18 Aug 2026
Release timing varies
gaps range from 8 days to 6 months
Rarely documented
notes for 5 of 54 stable releases
Nothing withdrawn
no release was ever pulled
4 years old
236 releases · first in 2022
One column per quarter.
Nothing published for this version
- Support IE8 (#2540) - Add ES2015 module build
Nothing published for this version
This is the first stable release of @remix-run/router, which provides all the underlying routing and data loading/mutation logic for react-router. You
This is the first stable release of @remix-run/router, which provides all the underlying routing and data loading/mutation logic for react-router. You should not be using this package directly unless you are authoring a routing library similar to react-router.
For an overview of the features provided by react-router, we recommend you go check out the docs, especially the feature overview and the tutorial.
For an overview of the features provided by @remix-run/router, please check out the README.
Thanks for your patience :) Big changes from v0.13.x to 1.0. While on the surface a lot of this just looks like shuffling around API, the entire codebase has been rewritten to handle some really great use cases, like loading routes and components on demand, session-based route matching, server rendering, integration with libs like redux and relay, and lots more.
But for now, here's how to translate the old API to the new one.
The new Router component is a property of the top-level module.
// v0.13.x
var Router = require('react-router');
var Route = Router.Route;
// v1.0
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
// or using ES Modules
import { Router, Route } from 'react-router';
// v0.13.x
Router.run(routes, (Handler) => {
render(<Handler/>, el);
})
// v1.0
render(<Router>{routes}</Router>, el)
// looks more like this:
render((
<Router>
<Route path="/" component={App}/>
</Router>
), el);
// or if you'd rather
render(<Router routes={routes}/>, el)
Locations are now called histories (that emit locations). You import them from the history package, not react router.
// v0.13.x
Router.run(routes, Router.BrowserHistory, (Handler) => {
render(<Handler/>, el);
})
// v1.0
import createBrowserHistory from 'history/lib/createBrowserHistory'
let history = createBrowserHistory()
render(<Router history={history}>{routes}</Router>, el)
If you do not specify a history type (as in the example above) then you will notice some unusual behavior after updating to 1.0.0. With the default hash based routing a querystring entry not defined by yourself will start appearing in your URLs called _k. An example of how it looks is this: ?_k=umhx1s
This is intended and part of createHashHistory (which is the default history approach used if one is not specified). You can read more about the feature here and how to opt out here.
You can still nest your routes as before, paths are inherited from parents just like before but prop names have changed.
// v0.13.x
<Route name="about" handler={About}/>
// v1.0
<Route path="about" component={About}/>
Named routes are gone (for now, see discussion)
Not found really confused people, mistaking not finding resources from your API for not matching a route. We've removed it completely since it's simple with a * path.
// v0.13.x
<NotFoundRoute handler={NoMatch}/>
// v1.0
<Route path="*" component={NoMatch}/>
// v0.13.x
<Redirect from="some/where/:id" to="somewhere/else/:id" params={{id: 2}}/>
// v1.0
// Works the same as before, except no params, just put them in the path
<Redirect from="/some/where/:id" to="/somewhere/else/2"/>
// v0.13.x
<Link to="user" params={{userId: user.id}}>Mateusz</Link>
// v1.0
// because named routes are gone, link to full paths, you no longer need
// to know the names of the parameters, and string templates are quite
// nice. Note that `query` has not changed.
<Link to={`/users/${user.id}`}>Mateusz</Link>
In 0.13.x links added the "active" class by default which you could override with activeClassName, or provide activeStyles. It's usually just a handful of navigation links that need this behavior.
Links no longer add the "active" class by default (its expensive and usually not necessary), you opt-in by providing one; if no activeClassName or activeStyles are provided, the link will not check if it's active.
// v0.13.x
<Link to="about">About</Link>
// v1.0
<Link to="/about" activeClassName="active">About</Link>
Because named routes are gone, a link to / with an index route at / will always be active. So we've introduced IndexLink that is only active when on exactly that path.
// v0.13.x
// with this route config
<Route path="/" handler={App}>
<DefaultRoute name="home" handler={Home}/>
<Route name="about" handler={About}/>
</Route>
// will be active only when home is active, not when about is active
<Link to="home">Home</Link>
// v1.0
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="about" component={About}/>
</Route>
// will be active only when home is active, not when about is active
<IndexLink to="/">Home</IndexLink>
This gives you more granular control of what causes a link to be active or not when there is an index route involved.
For consistency with React v0.14, returning false from a Link's onClick handler no longer prevents the transition. To prevent the transition, call e.preventDefault() instead.
RouteHandler is gone. Router now automatically populates this.props.children of your components based on the active route.
// v0.13.x
<RouteHandler/>
<RouteHandler someExtraProp={something}/>
// v1.0
{this.props.children}
{React.cloneElement(this.props.children, {someExtraProp: something})}
Note: React does not validate propTypes that are specified via cloneElement (see: facebook/react#4494). It is recommended to make such propTypes optional.
If you were using the Navigation mixin, use the History mixin instead.
// v0.13.x
var Assignment = React.createClass({
mixins: [ Navigation ],
navigateAfterSomethingHappened () {
this.transitionTo('/users', { userId: user.id }, query);
// this.replaceWith('/users', { userId: user.id }, query);
}
})
// v1.0
var Assignment = React.createClass({
mixins: [ History ],
navigateAfterSomethingHappened () {
// the router is now built on rackt/history, and it is a first class
// API in the router for navigating
this.history.pushState(null, `/users/${user.id}`, query);
// this.history.replaceState(null, `/users/${user.id}`, query);
}
})
The following Navigation methods are now also found on the history object, main difference again is there are no params or route names, just pathnames.
| v0.13 | v1.0 |
|---|---|
go(n) |
go(n) |
goBack() |
goBack() |
goForward() |
goForward() |
makeHref(routeName, params, query) |
createHref(pathname, query) |
makePath(routeName, params, query) |
createPath(pathname, query) |
// v0.13.x
var Assignment = React.createClass({
mixins: [ State ],
foo () {
this.getPath()
this.getParams()
// etc...
}
})
// v1.0
// if you are a route component...
<Route component={Assignment} />
var Assignment = React.createClass({
foo () {
this.props.location // contains path information
this.props.params // contains params
this.props.history.isActive
}
})
// if you're not a route component, you need to pass location down the
// tree or get the location from context. We will probably provide a
// higher order component that will do this for you but haven't yet.
// see further down for more information on what can be passed down
// via context
var Assignment = React.createClass({
contextTypes: {
location: React.PropTypes.object
},
foo () {
this.context.location
}
})
Here's a table of where you used to get stuff with the State mixin, and where you get it now if you're a route component (this.props)
| v0.13 (this) | v1.0 (this.props) |
|---|---|
getPath() |
location.pathname+location.search |
getPathname() |
location.pathname |
getParams() |
params |
getQuery() |
location.search |
getQueryParams() |
location.query |
getRoutes() |
routes |
isActive(to, params, query) |
history.isActive(pathname, query, onlyActiveOnIndex) |
Here is another table of properties you used to get via the State and where you can get it now if you are not a route component (this.context).
| v0.13 (this) | v1.0 (this.context) |
|---|---|
getPath() |
location.pathname+location.search |
getPathname() |
location.pathname |
getQuery() |
location.search |
getQueryParams() |
location.query |
isActive(to, params, query) |
history.isActive(pathname, query, indexOnly) |
Note not all State functionality can be accessed via context in v1.0. For example, params is not available via context.
We're developing scroll behaviors separately in the scroll-behavior library until we have a stable, robust implementation that we're happy with. Currently, scroll behaviors are exposed there as history enhancers:
import createHistory from 'history/lib/createBrowserHistory'
import useScroll from 'scroll-behavior/lib/useStandardScroll'
const history = useScroll(createHistory)()
willTransitionTo and willTransitionFromRoutes now define this behavior:
// v0.13.x
var Home = React.createClass({
statics: {
willTransitionTo (transition, params, query, callback) { }
willTransitionFrom (component, transition, params, query, callback) { }
}
})
// v1.0
<Route
component={Home}
onEnter={(location, replaceWith) => {}}
onLeave={() => {}}
/>
To cancel a "transition from", please refer to the Confirming Navigation guide.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
We are no longer replacing the Promise on loaderData with the value/error when it settles so it's now always a Promise.
c3406eb9: fix: Rename <Deferred> to <Await> (#9095)
Promise on loaderData with the value/error
when it settles so it's now always a Promise.<Deferred value={promise}> to
<Await resolve={promise}> for clarity, and it also now supports using
<Await> with raw promises from anywhere, not only those on loaderData
from a defer() call.
useAsyncValue/useAsyncErrorTo that end, they are available for use, but are subject to breaking changes in the next minor release._
feat: Deferred API Updates (#9070)
return deferred([ await critical(), lazy() ])return deferred(lazy())Deferrable/ResolvedDeferrable in favor of raw Promise's and AwaiteduseDeferredData until useLoaderData generic is decided in 6.5feat: Add createStaticRouter for @remix-run/router SSR usage (#9013)
Notable changes:
request is now the driving force inside the router utils, so that we can better handle Request instances coming form the server (as opposed to string and Path instances coming from the client)signal param from loader and action functions in favor of request.signalExample usage (Document Requests):
// Create a static handler
let { query } = unstable_createStaticHandler(routes);
// Perform a full-document query for the incoming Fetch Request. This will
// execute the appropriate action/loaders and return either the state or a
// Fetch Response in the case of redirects.
let state = await query(fetchRequest);
// If we received a Fetch Response back, let our server runtime handle directly
if (state instanceof Response) {
throw state;
}
// Otherwise, render our application providing the data routes and state
let html = ReactDOMServer.renderToString(
<React.StrictMode>
<DataStaticRouter routes={routes} state={state} />
</React.StrictMode>
);
Example usage (Data Requests):
// Create a static route handler
let { queryRoute } = unstable_createStaticHandler(routes);
// Perform a single-route query for the incoming Fetch Request. This will
// execute the appropriate singular action/loader and return either the raw
// data or a Fetch Response
let data = await queryRoute(fetchRequest);
// If we received a Fetch Response back, return it directly
if (data instanceof Response) {
return data;
}
// Otherwise, construct a Response from the raw data (assuming json here)
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json; charset=utf-8",
},
});
feat: SSR Updates for React Router (#9058)
Note: The Data-Router SSR aspects of @remix-run/router and react-router-dom are being released as unstable in this release (unstable_createStaticHandler and unstable_DataStaticRouter), and we plan to finalize them in a subsequent minor release once the kinks can be worked out with the Remix integration. To that end, they are available for use, but are subject to breaking changes in the next minor release.
useRenderDataRouter() in favor of <DataRouterProvider>/<DataRouter><DataStaticRouter>/<DataBrowserRouter>/<DataHashRouter>
window.__staticRouterHydrationData<DataStaticRouter hydrate={false}>hydrationData to <DataBrowserRouter>/<DataHashRouter><DataStaticRouter> now tracks it's own SSR error boundaries on StaticHandlerContextStaticHandlerContext now exposes statusCode/loaderHeaders/actionHeadersfoundMissingHydrationData check removed since Remix routes may have loaders (for modules) that don't return data for loaderDatafix: Handle fetcher 404s as normal boundary errors
deferred support to data routers (#9002)fix: properly handle submissions
<Form encType="multipart/form-data"> submissions (#8984)REPLACE navigation on form submissions if the action redirected. The redirect takes care of avoiding the back-button-resubmit scenario, so by using a PUSH we allow the back button to go back to the pre-submission form page (#8979)Capture fetcher errors at contextual route error boundaries
### Patch Changes - Fix missing dist files
dist filesNothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →