--- title: Upgrading from Remix order: 3 --- # Upgrading from Remix React Router v7 requires the following minimum versions: - `node@20` - `react@18` - `react-dom@18` React Router v7 is the next major version of Remix after v2 (see our ["Incremental Path to React 19" blog post][incremental-path-to-react-19] for more information). If you have enabled all [Remix v2 future flags][v2-future-flags], upgrading from Remix v2 to React Router v7 mainly involves updating dependencies. The majority of steps 2-8 can be automatically updated using a [codemod][codemod] created by community member [James Restall][jrestall]. ## 1. Adopt future flags **👉 Adopt future flags** Adopt all existing [future flags][v2-future-flags] in your Remix v2 application. ## 2. Update dependencies Most of the "shared" APIs that used to be re-exported through the runtime-specific packages (`@remix-run/node`, `@remix-run/cloudflare`, etc.) have all been collapsed into `react-router` in v7. So instead of importing from `@react-router/node` or `@react-router/cloudflare`, you'll import those directly from `react-router`. ```diff -import { redirect } from "@remix-run/node"; +import { redirect } from "react-router"; ``` The only APIs you should be importing from the runtime-specific packages in v7 are APIs that are specific to that runtime, such as `createFileSessionStorage` for Node and `createWorkersKVSessionStorage` for Cloudflare. **👉 Run the codemod (automated)** You can automatically update your packages and imports with the following [codemod][codemod]. This codemod updates all of your packages and imports. Be sure to commit any pending changes before running the codemod, in case you need to revert. ```shellscript nonumber npx codemod remix/2/react-router/upgrade ``` **👉 Install the new dependencies** After the codemod updates your dependencies, you need to install the dependencies to remove Remix packages and add the new React Router packages. ```shellscript nonumber npm install ``` **👉 Update your dependencies (manual)** If you prefer not to use the codemod, you can manually update your dependencies.
Expand to see a table of package name changes in alphabetical order | Remix v2 Package | | React Router v7 Package | | ---------------------------------- | --- | ------------------------------------------- | | `@remix-run/architect` | ➡️ | `@react-router/architect` | | `@remix-run/cloudflare` | ➡️ | `@react-router/cloudflare` | | `@remix-run/dev` | ➡️ | `@react-router/dev` | | `@remix-run/express` | ➡️ | `@react-router/express` | | `@remix-run/fs-routes` | ➡️ | `@react-router/fs-routes` | | `@remix-run/node` | ➡️ | `@react-router/node` | | `@remix-run/react` | ➡️ | `react-router` | | `@remix-run/route-config` | ➡️ | `@react-router/dev` | | `@remix-run/routes-option-adapter` | ➡️ | `@react-router/remix-routes-option-adapter` | | `@remix-run/serve` | ➡️ | `@react-router/serve` | | `@remix-run/server-runtime` | ➡️ | `react-router` | | `@remix-run/testing` | ➡️ | `react-router` |
## 3. Change `scripts` in `package.json` If you used the codemod you can skip this step as it was automatically completed. **👉 Update the scripts in your `package.json`** | Script | Remix v2 | | React Router v7 | | ----------- | ----------------------------------- | --- | ------------------------------------------ | | `dev` | `remix vite:dev` | ➡️ | `react-router dev` | | `build` | `remix vite:build` | ➡️ | `react-router build` | | `start` | `remix-serve build/server/index.js` | ➡️ | `react-router-serve build/server/index.js` | | `typecheck` | `tsc` | ➡️ | `react-router typegen && tsc` | ## 4. Add a `routes.ts` file If you used the codemod _and_ Remix v2 `v3_routeConfig` flag, you can skip this step as it was automatically completed. In React Router v7 you define your routes using the `app/routes.ts` file. View the [routing documentation][routing] for more information. **👉 Update dependencies (if using Remix v2 `v3_routeConfig` flag)** ```diff filename=app/routes.ts -import { type RouteConfig } from "@remix-run/route-config"; -import { flatRoutes } from "@remix-run/fs-routes"; -import { remixRoutesOptionAdapter } from "@remix-run/routes-option-adapter"; +import { type RouteConfig } from "@react-router/dev/routes"; +import { flatRoutes } from "@react-router/fs-routes"; +import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; export default [ // however your routes are defined ] satisfies RouteConfig; ``` **👉 Add a `routes.ts` file (if _not_ using Remix v2 `v3_routeConfig` flag)** ```shellscript nonumber touch app/routes.ts ``` For backwards-compatibility, there are a few ways to adopt `routes.ts` to align with your route setup in Remix v2: 1. If you were using the "flat routes" [file-based convention][fs-routing], you can continue to use that via the new `@react-router/fs-routes` package: ```ts filename=app/routes.ts import { type RouteConfig } from "@react-router/dev/routes"; import { flatRoutes } from "@react-router/fs-routes"; export default flatRoutes() satisfies RouteConfig; ``` 2. If you were using the "nested" convention from Remix v1 via the `@remix-run/v1-route-convention` package, you can continue using that as well in conjunction with `@react-router/remix-routes-option-adapter`: ```ts filename=app/routes.ts import { type RouteConfig } from "@react-router/dev/routes"; import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; import { createRoutesFromFolders } from "@remix-run/v1-route-convention"; export default remixRoutesOptionAdapter( createRoutesFromFolders ) satisfies RouteConfig; ``` 3. If you were using the `routes` option to define config-based routes, you can keep that config via `@react-router/remix-routes-option-adapter`: ```ts filename=app/routes.ts import { type RouteConfig } from "@react-router/dev/routes"; import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter"; export default remixRoutesOptionAdapter( (defineRoutes) => { return defineRoutes((route) => { route("/", "home/route.tsx", { index: true }); route("about", "about/route.tsx"); route("", "concerts/layout.tsx", () => { route("trending", "concerts/trending.tsx"); route(":city", "concerts/city.tsx"); }); }); } ) satisfies RouteConfig; ``` - Be sure to also remove the `routes` option in your `vite.config.ts`: ```diff filename=vite.config.ts export default defineConfig({ plugins: [ remix({ ssr: true, - ignoredRouteFiles: ['**/*'], - routes(defineRoutes) { - return defineRoutes((route) => { - route("/somewhere/cool/*", "catchall.tsx"); - }); - }, }) tsconfigPaths(), ], }); ``` ## 5. Add a React Router config **👉 Add `react-router.config.ts` your project** The config that was previously passed to the `remix` plugin in `vite.config.ts` is now exported from `react-router.config.ts`. Note: At this point you should remove the v3 future flags you added in step 1. ```shellscript nonumber touch react-router.config.ts ``` ```diff filename=vite.config.ts export default defineConfig({ plugins: [ - remix({ - ssr: true, - future: {/* all the v3 flags */} - }), + reactRouter(), tsconfigPaths(), ], }); ``` ```diff filename=react-router.config.ts +import type { Config } from "@react-router/dev/config"; +export default { + ssr: true, +} satisfies Config; ``` ## 6. Add React Router plugin to `vite.config` If you used the codemod you can skip this step as it was automatically completed. **👉 Add `reactRouter` plugin to `vite.config`** Change `vite.config.ts` to import and use the new `reactRouter` plugin from `@react-router/dev/vite`: ```diff filename=vite.config.ts -import { vitePlugin as remix } from "@remix-run/dev"; +import { reactRouter } from "@react-router/dev/vite"; import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; export default defineConfig({ plugins: [ - remix(), + reactRouter(), tsconfigPaths(), ], }); ``` ## 7. Enable type safety If you are not using TypeScript, you can skip this step. React Router automatically generates types for your route modules into a `.react-router/` directory at the root of your app. This directory is fully managed by React Router and should be gitignore'd. Learn more about the [new type safety features][type-safety]. **👉 Add `.react-router/` to `.gitignore`** ```txt .react-router/ ``` **👉 Update `tsconfig.json`** Update the `types` field in your `tsconfig.json` to include: - `.react-router/types/**/*` path in the `include` field - The appropriate `@react-router/*` package in the `types` field - `rootDirs` for simplified relative imports ```diff filename=tsconfig.json { "include": [ /* ... */ + ".react-router/types/**/*" ], "compilerOptions": { - "types": ["@remix-run/node", "vite/client"], + "types": ["@react-router/node", "vite/client"], /* ... */ + "rootDirs": [".", "./.react-router/types"] } } ``` ## 8. Rename components in entry files If you used the codemod you can skip this step as it was automatically completed. If you have an `entry.server.tsx` and/or an `entry.client.tsx` file in your application, you will need to update the main components in these files: ```diff filename=app/entry.server.tsx -import { RemixServer } from "@remix-run/react"; +import { ServerRouter } from "react-router"; -, +, ``` ```diff filename=app/entry.client.tsx -import { RemixBrowser } from "@remix-run/react"; +import { HydratedRouter } from "react-router/dom"; hydrateRoot( document, - + , ); ``` ## 9. Update types for `AppLoadContext` If you were using `remix-serve` you can skip this step. This is only applicable if you were using a custom server in Remix v2. Since React Router can be used as both a React framework _and_ a stand-alone routing library, the `context` argument for `LoaderFunctionArgs` and `ActionFunctionArgs` is now optional and typed as `any` by default. You can register types for your load context to get type safety for your loaders and actions. 👉 **Register types for your load context** Before you migrate to the new `Route.LoaderArgs` and `Route.ActionArgs` types, you can temporarily augment `LoaderFunctionArgs` and `ActionFunctionArgs` with your load context type to ease migration. ```ts filename=app/env.ts declare module "react-router" { // Your AppLoadContext used in v2 interface AppLoadContext { whatever: string; } // TODO: remove this once we've migrated to `Route.LoaderArgs` instead for our loaders interface LoaderFunctionArgs { context: AppLoadContext; } // TODO: remove this once we've migrated to `Route.ActionArgs` instead for our actions interface ActionFunctionArgs { context: AppLoadContext; } } export {}; // necessary for TS to treat this as a module ``` Using `declare module` to register types is a standard TypeScript technique called [module augmentation][ts-module-augmentation]. You can do this in any TypeScript file covered by your `tsconfig.json`'s `include` field, but we recommend a dedicated `env.ts` within your app directory. 👉 **Use the new types** Once you adopt the [new type generation][type-safety], you can remove the `LoaderFunctionArgs`/`ActionFunctionArgs` augmentations and use the `context` argument from [`Route.LoaderArgs`][server-loaders] and [`Route.ActionArgs`][server-actions] instead. ```ts filename=app/env.ts declare module "react-router" { // Your AppLoadContext used in v2 interface AppLoadContext { whatever: string; } } export {}; // necessary for TS to treat this as a module ``` ```ts filename=app/routes/my-route.tsx import type { Route } from "./+types/my-route"; export function loader({ context }: Route.LoaderArgs) {} // { whatever: string } ^^^^^^^ export function action({ context }: Route.ActionArgs) {} // { whatever: string } ^^^^^^^ ``` Congratulations! You are now on React Router v7. Go ahead and run your application to make sure everything is working as expected. [incremental-path-to-react-19]: https://remix.run/blog/incremental-path-to-react-19 [v2-future-flags]: https://remix.run/docs/start/future-flags [routing]: ../start/framework/routing [fs-routing]: ../how-to/file-route-conventions [v7-changelog-types]: https://github.com/remix-run/react-router/blob/release-next/CHANGELOG.md#type-safety-improvements [server-loaders]: ../start/framework/data-loading#server-data-loading [server-actions]: ../start/framework/actions#server-actions [ts-module-augmentation]: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation [type-safety]: ../explanation/type-safety [codemod]: https://codemod.com/registry/remix-2-react-router-upgrade [jrestall]: https://github.com/jrestall