# Solid Router: fine-grained routing for SolidJS, with four URL strategies

> Solid Router is the MIT licensed universal router for SolidJS, inspired by Ember and React Router, offering history, hash, memory and static routing modes plus preload functions for parallel data fetching and a set of router primitives. It suits a Solid developer building a multi-page-feeling single page app, and it is the wrong tool if you want the router to be framework agnostic, since it is built on Solid's reactivity model.

**solidjs/solid-router** — A universal router for Solid inspired by Ember and React Router

- Repository: https://github.com/solidjs/solid-router
- Stars: 1,320 · Forks: 186
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/solidjs-solid-router

## The package is @solidjs/router, and the API is component-shaped

The project is described as a universal router for Solid inspired by Ember and React Router, and the installation is a single package.

```bash
# use preferred package manager
npm add @solidjs/router
```

The setup then renders a Router component, which matches on the URL to display the desired page.

```jsx
import { render } from "solid-js/web";
import { Router } from "@solidjs/router";

render(() => <Router />, document.getElementById("app"));
```

The claim in the README is that the router brings fine-grained reactivity to route navigation, enabling a single-page application to become multi-paged without full page reloads, and that it is fully integrated into the SolidJS ecosystem with declarative syntax, universal rendering and parallel data fetching. The package is published as @solidjs/router at version 1.0.0 in the package.json, with the author listed as Ryan Carniato and Ryan Turnquist as a contributor.

## Routes are components, and a root layout wraps them

Routes are configured with JSX, and there are three things to know. Each route is added to a Router using the Route component with a path and a component to render. A root level layout can be provided, and the README explains that this always stays and will not update on page change, making it the right place for top level navigation and context providers.

```jsx
const App = (props) => (
  <>
    <h1>My Site with lots of pages</h1>
    {props.children}
  </>
);

render(
  () => (
    <Router root={App}>
      <Route path="/users" component={Users} />
      <Route path="/" component={Home} />
    </Router>
  ),
  document.getElementById("app")
);
```

A catch-all route is the third piece, created with a star and optionally a parameter name to capture the rest of the path, which is how the 404 page is handled at any nesting level.

```jsx
<Route path="*404" component={NotFound} />
```

The README also notes that routes can be defined as components or as an object, which is the config based routing mode covered in its own section.

## Lazy loading and preload functions solve different halves of the wait

Route components can be lazy loaded with Solid's lazy helper, so a component is only fetched when you navigate to the path that needs it.

```jsx
const Users = lazy(() => import("./pages/Users"));
const Home = lazy(() => import("./pages/Home"));
```

That handles the code split. The data half is handled by the preload functions, described in the feature list as parallel data fetching following the render-as-you-fetch pattern, and by the data APIs with caching, which the README describes as reactive data fetching with deduplication and revalidation. Together they are the reason the router claims better performance, since a navigation can start its data request before the new view is even mounted. The distinction between the two is worth holding on to, because a lazy component still shows a loading state while its data is in flight.

## Four routing modes, and the choice is not cosmetic

The feature list enumerates all routing modes, and each is a separate component. History based routing is for standard browser navigation. Hash based routing navigates on the URL hash, which matters when you cannot control server rewrites. Static routing exists for server-side rendering. Memory based routing is for testing in non-browser environments, which is the one most projects underestimate, since it is what lets a test assert on navigation without a real URL bar. The universal rendering claim, that the same routes render on client and server, is what ties static and history modes together.

## The primitives are reactive hooks, not a context value

The router primitives section lists useParams for dynamic route parameters, useNavigate for programmatic navigation, useLocation for the current location, useSearchParams for the query string, useIsRouting to know whether a navigation is in flight, useMatch to test whether a path matches, useCurrentMatches for the full active match chain, and useBeforeLeave to guard a navigation. That last one is the interesting primitive, since it is how a form with unsaved changes blocks a route change, and in a fine-grained framework it can be a signal rather than a wrapper around every link. Dynamic route parameters support URL patterns with parameters, optional segments and wildcards, and nested routes are covered in their own section.

## The repository is a pnpm monorepo with type benchmarks

The root listing shows a TypeScript package built with tsc and then bundled with rollup, with a babel.config.cjs, a rollup.config.js, vitest.config.ts and separate tsconfig.json and tsconfig.test.json. Two directories are unusual and worth a look. The .type-bench/ directory suggests the team measures the type-level cost of the router's types, which matters for a library whose selling point is type safety and whose users compile in the browser build. The .shake-check/ directory points at API surface checking, the practice of detecting unintended changes to a package's exported API between versions. Releases are cut with changesets, since the .changeset/ directory and the release script running changeset publish are both present, and the release tags are on the 2.0.0-next series with next.40 dated 2026-10-14, so the stable 1.0.0 in package.json and the prerelease tags are two different lines of the same project.

## A peer dependency on Solid, and a small but real constraint

The package metadata makes the coupling explicit. solid-js is a peer dependency at ^1.8.6 rather than a direct dependency, which is the right choice for a library, since two copies of Solid in one application would break reactivity across the boundary. The build then compiles with babel-preset-solid and vite-plugin-solid, the test script runs vitest run followed by a separate type check against tsconfig.test.json, and the format script covers both src and test. The exports map is conditional, with a solid condition pointing at dist/index.jsx and a default pointing at dist/index.js, which is how a Solid library ships both compiled and source forms. The package is marked sideEffects false and ships only the dist directory, and the declared package manager is pnpm 10.19.0 with a lockfile hash.

## Conclusion

Solid Router fits a SolidJS application that needs more than a single view without a full page reload, since the route primitives are reactive signals rather than a context re-render, and the preload mechanism lets data fetching start before the navigation completes. It is a poor fit for a project that wants to swap its view layer, since the router is Solid specific, and a poor fit if your team is coming from React Router and expects the same mental model, since the README explicitly says it was inspired by Ember and React Router rather than being a port. Verify first which routing mode you need, since the static mode exists for server-side rendering and the memory mode exists for tests in non-browser environments, and pin a version carefully because the release tags sit on the 2.0.0-next series.

## FAQ

### What routing modes does Solid Router support?

Four. History based for standard browser navigation, hash based for URL hash navigation, static routing for server-side rendering, and memory based for testing in non-browser environments, each exposed as its own component.

### How do I lazy load route components in Solid Router?

Use Solid's lazy helper on the component you pass to Route, for example const Users = lazy(() => import("./pages/Users")), so the module is only fetched when you navigate to that path.

### What are the router primitives in Solid Router?

useParams, useNavigate, useLocation, useSearchParams, useIsRouting, useMatch, useCurrentMatches and useBeforeLeave, the last of which lets you guard a navigation, for instance when a form has unsaved changes.

### How is Solid Router released?

With changesets, since the repository carries a .changeset directory and the release script runs pnpm build followed by changeset publish. The build itself removes dist, runs tsc and then rollup, and the tests run vitest plus a separate type check.

## Sources

- [Issues](https://github.com/solidjs/solid-router/issues)
- [License: MIT](https://github.com/solidjs/solid-router/blob/main/LICENSE)
- [README](https://github.com/solidjs/solid-router/blob/main/README.md)
- [Releases](https://github.com/solidjs/solid-router/releases)
- [solidjs/solid-router on GitHub](https://github.com/solidjs/solid-router)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/solidjs-solid-router
