Migration Guide
Migrating from react-router to @equinor/fusion-framework-react-router
This guide covers migrating an app that uses react-router directly to the Fusion Framework router integration.
Why migrate?
The Fusion router wraps React Router v7 and adds:
- Automatic wiring of
historyandbasenamefrom the Fusion navigation module β no manual setup. - Typed
fusioncontext injected into every loader, action, and component β no prop drilling or extra React contexts. - A file-style route DSL (
layout,index,route,prefix) that replaces hand-builtRouteObjecttrees. - Route schema generation for portals, manifests, and documentation tooling.
Step 1 β Replace the router setup
Before (plain React Router):
import { createBrowserRouter, RouterProvider } from 'react-router';
const router = createBrowserRouter([
{ path: '/', element: <HomePage /> },
{ path: '/products/:id', element: <ProductPage /> },
]);
export default function App() {
return <RouterProvider router={router} />;
}After (Fusion router):
import { Router } from '@equinor/fusion-framework-react-router';
const routes = [
{ path: '/', Component: HomePage },
{ path: '/products/:id', Component: ProductPage },
];
export default function App() {
return <Router routes={routes} />;
}<Router> picks up history and basename from the Fusion navigation module automatically. You do not create or manage a router instance.
Step 2 β Replace the route DSL (recommended)
Instead of RouteObject[], use the Fusion DSL for a cleaner, file-based structure:
// src/pages/index.ts
import { layout, index, route, prefix } from '@equinor/fusion-framework-react-router/routes';
export const pages = layout('./MainLayout.tsx', [
index('./HomePage.tsx'),
prefix('products', [
index('./ProductsPage.tsx'),
route(':id', './ProductPage.tsx'),
]),
]);The Vite plugin transforms these DSL calls into standard RouteObject code at build time. See the Vite plugin section in the router module docs.
Step 3 β Replace loader and action signatures
Fusion injects a fusion argument into every loader and action. Update your function signatures:
Before:
export async function loader({ params }: LoaderFunctionArgs) {
return fetch(`/api/products/${params.id}`);
}After:
import type { LoaderFunctionArgs } from '@equinor/fusion-framework-react-router';
export async function clientLoader({ params, fusion }: LoaderFunctionArgs<{ id: string }>) {
const client = fusion.modules.http.createHttpClient('products');
return client.json(`/products/${params.id}`);
}The fusion.modules object exposes all configured Fusion modules. The fusion.context object exposes any custom context passed to <Router context={...} />.
Step 4 β Replace component props
Route components receive loaderData, actionData, and fusion as props instead of calling hooks:
Before:
import { useLoaderData } from 'react-router';
export default function ProductPage() {
const data = useLoaderData();
return <h1>{data.name}</h1>;
}After:
import type { RouteComponentProps } from '@equinor/fusion-framework-react-router';
export default function ProductPage({ loaderData }: RouteComponentProps<{ name: string }>) {
return <h1>{loaderData.name}</h1>;
}Step 5 β Replace hook imports
All standard React Router hooks are re-exported from the Fusion router package. Replace the import source:
// Before
import { useNavigate, useParams, useLocation } from 'react-router';
// After
import { useNavigate, useParams, useLocation } from '@equinor/fusion-framework-react-router';Step 6 β Remove react-router from your dependencies
Once all imports are updated, remove react-router from your package.json. It is bundled as a direct dependency of @equinor/fusion-framework-react-router and will always be present β adding it separately risks bundling two copies of the router.
pnpm remove react-routerCommon questions
Can I still use useLoaderData and useParams hooks?
Yes. They are re-exported from @equinor/fusion-framework-react-router and work exactly as in React Router. The prop-based API is optional and preferred for type safety.
Can I mix RouteObject[] and the DSL?
Yes. <Router> accepts both. You can migrate route by route.
What about <Outlet />, <Link />, <NavLink />?
All re-exported from @equinor/fusion-framework-react-router. No import changes needed beyond the source package.