UNPKG

14.2 kB Markdown View Raw
1---
2title: Upgrading from Remix
3order: 3
4---
5
6# Upgrading from Remix
7
8<docs-info>
9
10React Router v7 requires the following minimum versions:
11
12- `node@20`
13- `react@18`
14- `react-dom@18`
15
16</docs-info>
17
18React 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).
19
20If you have enabled all [Remix v2 future flags][v2-future-flags], upgrading from Remix v2 to React Router v7 mainly involves updating dependencies.
21
22<docs-info>
23
24The majority of steps 2-8 can be automatically updated using a [codemod][codemod] created by community member [James Restall][jrestall].
25
26</docs-info>
27
28## 1. Adopt future flags
29
30**👉 Adopt future flags**
31
32Adopt all existing [future flags][v2-future-flags] in your Remix v2 application.
33
34## 2. Update dependencies
35
36Most 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`.
37
38```diff
39-import { redirect } from "@remix-run/node";
40+import { redirect } from "react-router";
41```
42
43The 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.
44
45**👉 Run the codemod (automated)**
46
47You 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.
48
49```shellscript nonumber
50npx codemod remix/2/react-router/upgrade
51```
52
53**👉 Install the new dependencies**
54
55After the codemod updates your dependencies, you need to install the dependencies to remove Remix packages and add the new React Router packages.
56
57```shellscript nonumber
58npm install
59```
60
61**👉 Update your dependencies (manual)**
62
63If you prefer not to use the codemod, you can manually update your dependencies.
64
65<details>
66<summary>Expand to see a table of package name changes in alphabetical order</summary>
67
68| Remix v2 Package | | React Router v7 Package |
69| ---------------------------------- | --- | ------------------------------------------- |
70| `@remix-run/architect` | ➡️ | `@react-router/architect` |
71| `@remix-run/cloudflare` | ➡️ | `@react-router/cloudflare` |
72| `@remix-run/dev` | ➡️ | `@react-router/dev` |
73| `@remix-run/express` | ➡️ | `@react-router/express` |
74| `@remix-run/fs-routes` | ➡️ | `@react-router/fs-routes` |
75| `@remix-run/node` | ➡️ | `@react-router/node` |
76| `@remix-run/react` | ➡️ | `react-router` |
77| `@remix-run/route-config` | ➡️ | `@react-router/dev` |
78| `@remix-run/routes-option-adapter` | ➡️ | `@react-router/remix-routes-option-adapter` |
79| `@remix-run/serve` | ➡️ | `@react-router/serve` |
80| `@remix-run/server-runtime` | ➡️ | `react-router` |
81| `@remix-run/testing` | ➡️ | `react-router` |
82
83</details>
84
85## 3. Change `scripts` in `package.json`
86
87<docs-info>
88
89If you used the codemod you can skip this step as it was automatically completed.
90
91</docs-info>
92
93**👉 Update the scripts in your `package.json`**
94
95| Script | Remix v2 | | React Router v7 |
96| ----------- | ----------------------------------- | --- | ------------------------------------------ |
97| `dev` | `remix vite:dev` | ➡️ | `react-router dev` |
98| `build` | `remix vite:build` | ➡️ | `react-router build` |
99| `start` | `remix-serve build/server/index.js` | ➡️ | `react-router-serve build/server/index.js` |
100| `typecheck` | `tsc` | ➡️ | `react-router typegen && tsc` |
101
102## 4. Add a `routes.ts` file
103
104<docs-info>
105
106If you used the codemod _and_ Remix v2 `v3_routeConfig` flag, you can skip this step as it was automatically completed.
107
108</docs-info>
109
110In React Router v7 you define your routes using the `app/routes.ts` file. View the [routing documentation][routing] for more information.
111
112**👉 Update dependencies (if using Remix v2 `v3_routeConfig` flag)**
113
114```diff filename=app/routes.ts
115-import { type RouteConfig } from "@remix-run/route-config";
116-import { flatRoutes } from "@remix-run/fs-routes";
117-import { remixRoutesOptionAdapter } from "@remix-run/routes-option-adapter";
118+import { type RouteConfig } from "@react-router/dev/routes";
119+import { flatRoutes } from "@react-router/fs-routes";
120+import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter";
121
122export default [
123 // however your routes are defined
124] satisfies RouteConfig;
125```
126
127**👉 Add a `routes.ts` file (if _not_ using Remix v2 `v3_routeConfig` flag)**
128
129```shellscript nonumber
130touch app/routes.ts
131```
132
133For backwards-compatibility, there are a few ways to adopt `routes.ts` to align with your route setup in Remix v2:
134
1351. 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:
136
137 ```ts filename=app/routes.ts
138 import { type RouteConfig } from "@react-router/dev/routes";
139 import { flatRoutes } from "@react-router/fs-routes";
140
141 export default flatRoutes() satisfies RouteConfig;
142 ```
143
1442. 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`:
145
146 ```ts filename=app/routes.ts
147 import { type RouteConfig } from "@react-router/dev/routes";
148 import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter";
149 import { createRoutesFromFolders } from "@remix-run/v1-route-convention";
150
151 export default remixRoutesOptionAdapter(
152 createRoutesFromFolders,
153 ) satisfies RouteConfig;
154 ```
155
1563. If you were using the `routes` option to define config-based routes, you can keep that config via `@react-router/remix-routes-option-adapter`:
157
158 ```ts filename=app/routes.ts
159 import { type RouteConfig } from "@react-router/dev/routes";
160 import { remixRoutesOptionAdapter } from "@react-router/remix-routes-option-adapter";
161
162 export default remixRoutesOptionAdapter(
163 (defineRoutes) => {
164 return defineRoutes((route) => {
165 route("/", "home/route.tsx", { index: true });
166 route("about", "about/route.tsx");
167 route("", "concerts/layout.tsx", () => {
168 route("trending", "concerts/trending.tsx");
169 route(":city", "concerts/city.tsx");
170 });
171 });
172 },
173 ) satisfies RouteConfig;
174 ```
175
176 - Be sure to also remove the `routes` option in your `vite.config.ts`:
177
178 ```diff filename=vite.config.ts
179 export default defineConfig({
180 plugins: [
181 remix({
182 ssr: true,
183 - ignoredRouteFiles: ['**/*'],
184 - routes(defineRoutes) {
185 - return defineRoutes((route) => {
186 - route("/somewhere/cool/*", "catchall.tsx");
187 - });
188 - },
189 })
190 tsconfigPaths(),
191 ],
192 });
193 ```
194
195## 5. Add a React Router config
196
197**👉 Add `react-router.config.ts` your project**
198
199The config that was previously passed to the `remix` plugin in `vite.config.ts` is now exported from `react-router.config.ts`.
200
201Note: At this point you should remove the v3 future flags you added in step 1.
202
203```shellscript nonumber
204touch react-router.config.ts
205```
206
207```diff filename=vite.config.ts
208export default defineConfig({
209 plugins: [
210- remix({
211- ssr: true,
212- future: {/* all the v3 flags */}
213- }),
214+ reactRouter(),
215 tsconfigPaths(),
216 ],
217});
218```
219
220```diff filename=react-router.config.ts
221+import type { Config } from "@react-router/dev/config";
222+export default {
223+ ssr: true,
224+} satisfies Config;
225```
226
227## 6. Add React Router plugin to `vite.config`
228
229<docs-info>
230
231If you used the codemod you can skip this step as it was automatically completed.
232
233</docs-info>
234
235**👉 Add `reactRouter` plugin to `vite.config`**
236
237Change `vite.config.ts` to import and use the new `reactRouter` plugin from `@react-router/dev/vite`:
238
239```diff filename=vite.config.ts
240-import { vitePlugin as remix } from "@remix-run/dev";
241+import { reactRouter } from "@react-router/dev/vite";
242import { defineConfig } from "vite";
243import tsconfigPaths from "vite-tsconfig-paths";
244
245export default defineConfig({
246 plugins: [
247- remix(),
248+ reactRouter(),
249 tsconfigPaths(),
250 ],
251});
252```
253
254## 7. Enable type safety
255
256<docs-info>
257
258If you are not using TypeScript, you can skip this step.
259
260</docs-info>
261
262React 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].
263
264**👉 Add `.react-router/` to `.gitignore`**
265
266```txt
267.react-router/
268```
269
270**👉 Update `tsconfig.json`**
271
272Update the `types` field in your `tsconfig.json` to include:
273
274- `.react-router/types/**/*` path in the `include` field
275- The appropriate `@react-router/*` package in the `types` field
276- `rootDirs` for simplified relative imports
277
278```diff filename=tsconfig.json
279{
280 "include": [
281 /* ... */
282+ ".react-router/types/**/*"
283 ],
284 "compilerOptions": {
285- "types": ["@remix-run/node", "vite/client"],
286+ "types": ["@react-router/node", "vite/client"],
287 /* ... */
288+ "rootDirs": [".", "./.react-router/types"]
289 }
290}
291```
292
293## 8. Rename components in entry files
294
295<docs-info>
296
297If you used the codemod you can skip this step as it was automatically completed.
298
299</docs-info>
300
301If 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:
302
303```diff filename=app/entry.server.tsx
304-import { RemixServer } from "@remix-run/react";
305+import { ServerRouter } from "react-router";
306
307-<RemixServer context={remixContext} url={request.url} />,
308+<ServerRouter context={remixContext} url={request.url} />,
309```
310
311```diff filename=app/entry.client.tsx
312-import { RemixBrowser } from "@remix-run/react";
313+import { HydratedRouter } from "react-router/dom";
314
315hydrateRoot(
316 document,
317 <StrictMode>
318- <RemixBrowser />
319+ <HydratedRouter />
320 </StrictMode>,
321);
322```
323
324## 9. Update types for `AppLoadContext`
325
326<docs-info>
327
328If you were using `remix-serve` you can skip this step. This is only applicable if you were using a custom server in Remix v2.
329
330</docs-info>
331
332Since 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.
333
334👉 **Register types for your load context**
335
336Before 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.
337
338```ts filename=app/env.ts
339declare module "react-router" {
340 // Your AppLoadContext used in v2
341 interface AppLoadContext {
342 whatever: string;
343 }
344
345 // TODO: remove this once we've migrated to `Route.LoaderArgs` instead for our loaders
346 interface LoaderFunctionArgs {
347 context: AppLoadContext;
348 }
349
350 // TODO: remove this once we've migrated to `Route.ActionArgs` instead for our actions
351 interface ActionFunctionArgs {
352 context: AppLoadContext;
353 }
354}
355
356export {}; // necessary for TS to treat this as a module
357```
358
359<docs-info>
360
361Using `declare module` to register types is a standard TypeScript technique called [module augmentation][ts-module-augmentation].
362You 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.
363
364</docs-info>
365
366👉 **Use the new types**
367
368Once 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.
369
370```ts filename=app/env.ts
371declare module "react-router" {
372 // Your AppLoadContext used in v2
373 interface AppLoadContext {
374 whatever: string;
375 }
376}
377
378export {}; // necessary for TS to treat this as a module
379```
380
381```ts filename=app/routes/my-route.tsx
382import type { Route } from "./+types/my-route";
383
384export function loader({ context }: Route.LoaderArgs) {}
385// { whatever: string } ^^^^^^^
386
387export function action({ context }: Route.ActionArgs) {}
388// { whatever: string } ^^^^^^^
389```
390
391Congratulations! You are now on React Router v7. Go ahead and run your application to make sure everything is working as expected.
392
393[incremental-path-to-react-19]: https://remix.run/blog/incremental-path-to-react-19
394[v2-future-flags]: https://remix.run/docs/start/future-flags
395[routing]: ../start/framework/routing
396[fs-routing]: ../how-to/file-route-conventions
397[v7-changelog-types]: https://github.com/remix-run/react-router/blob/release-next/CHANGELOG.md#type-safety-improvements
398[server-loaders]: ../start/framework/data-loading#server-data-loading
399[server-actions]: ../start/framework/actions#server-actions
400[ts-module-augmentation]: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
401[type-safety]: ../explanation/type-safety
402[codemod]: https://app.codemod.com/registry/remix/2/react-router/upgrade
403[jrestall]: https://github.com/jrestall