React Router 7 Migration
This guide outlines the necessary steps to migrate a Hydrogen storefront with Remix to one with React Router 7. This will include:
- Updating
@shopify/hydrogenand@shopify/hydrogen-reactto version2025.7.0+ - Updating
@pack/hydrogenand@pack/reactto3.0.0and4.0.0, respectively - Replacing imports from
@remix-runwithreact-router - All required code, config or import changes
Before proceeding, the following migrations must be done beforehand:
Things to Consider
For every task under Manual Setup , there is a corresponding prompt under LLM Prompts that may be passed into an LLM for automating each task. These prompts have been tested internally using the IDE Cursor or the Claude Code extension for VS Code
If using Cursor, adjust the chat settings accordingly:
- Turn on
Agentmode - Turn on
Auto-Run Modeto allow agent to write files without asking for permission each time'
If using Claude Code for VS Code, certain prompts may have the chat asking for permission for every bash command; in that case, approve each one as they come in. A note is left for the LLM in the prompt to hopefully prevent/limit this.
Note: These LLM prompts are tested with Pack storefronts that:
- Are built off Pack's Blueprint template
- Have not deviated significantly from the Blueprint template
In case of more custom builds, review each prompt and edit as needed to work within the codebase. Or follow the manual steps and ensure changes are made to the appopriate files and blocks of code.
Manual Setup
Dependency Updates
- Update or add the following packages accordingly:
- "@shopify/hydrogen": "2025.7.3"
- "@shopify/hydrogen-react": "2025.7.2"
- "@shopify/cli": "^3.88.1"
- "@shopify/cli-hydrogen": "^11.1.6"
- "react-router": "7.12.0"
- "react-router-dom": "7.12.0"
- "@react-router/dev": "7.12.0"
- "@react-router/fs-routes": "7.12.0" (in devDependencies)
- "@shopify/mini-oxygen": "^4.0.0"
- "vite": "^6.2.4"
- "@pack/hydrogen": "3.0.0"
- "@pack/react": "4.0.0"
- Remove following packages:
- "@remix-run/react"
- "@shopify/remix-oxygen"
- "@remix-run/dev"
- "@remix-run/eslint-config"
- "@remix-run/fs-routes"
- "@remix-run/route-config"
- Update node version to 20, so:
- In
package.json, change:"node": ">=18.0.0"to"node": ">=20.0.0" - In
.nvmrc, changev18tov20
- Delete
node_modulesandpackage-lock.json - Run
npm install
React Router Config File
Add react-router.config.ts to the root of the repo:
import type {Config} from '@react-router/dev/config';
import {hydrogenPreset} from '@shopify/hydrogen/react-router-preset';
/**
* This configuration uses the official Hydrogen preset to provide optimal
* React Router settings for Shopify Oxygen deployment. The preset enables
* validated performance optimizations while ensuring compatibility.
*/
export default {
presets: [hydrogenPreset()],
future: {
// Disable middleware to use legacy context pattern (context.storefront vs context.get())
// This is required until route files are migrated to use context.get(hydrogenContext.*)
v8_middleware: false,
},
} satisfies Config;
Server.ts Update
In server.ts:
- Replace
import * as remixBuild from 'virtual:remix/server-build';withimport * as serverBuild from 'virtual:react-router/server-build'; - Update the import for
createRequestHandlerandgetStorefrontHeaderto be from@shopify/hydrogen/oxygenopposed to@shopify/remix-oxygen - Replace
build: remixBuildwithbuild: serverBuildwithincreateRequestHandler - If
testSessionis not being passed intocreatePackClientdo the following. Note, this is not a required step for RR7 migration, but to address the eslint error:
- Import
PackTestSessionfrom@pack/hydrogen - Fetch
packTestSession
const [cache, session, packSession, packTestSession] = await Promise.all([
caches.open('hydrogen'),
AppSession.init(request, [env.SESSION_SECRET]),
PackSession.init(request, [env.SESSION_SECRET]),
PackTestSession.init(request, [env.SESSION_SECRET]),
]);
- Pass in
packTestSessionastestSessionto `createPackClient
Vite Config
In vite.config.ts
- Replace
import {vitePlugin as remix} from '@remix-run/dev';withimport {reactRouter} from '@react-router/dev/vite'; - Remove the
remix({...})plugin from thepluginsarray, and addreactRouter()instead - Remove any
remixrelated dependencies from thessr.optimizeDeps.includeandoptimizeDeps.includearrays, e.g.@remix-run/dev/server-build - Add
react-routerto thessr.optimizeDeps.includearray - Add in this
resolveconfig to thessrobject
resolve: {
conditions: ['workerd', 'worker', 'browser'],
externalConditions: ['workerd', 'worker'],
},
- Add this custom plugin above
export default defineConfig
/**
* Plugin to redirect vfile's Node.js imports to browser-compatible versions.
* This fixes "No such module node:path" errors on Oxygen deployment.
*/
function vfileBrowserPlugin(): Plugin {
return {
name: 'vfile-browser',
enforce: 'pre',
resolveId(id, importer) {
// Redirect vfile's internal imports to browser versions
if (importer?.includes('node_modules/vfile/')) {
// Get the vfile package root directory
const vfileRoot = importer.substring(
0,
importer.indexOf('node_modules/vfile/') +
'node_modules/vfile/'.length,
);
if (id === '#minpath') {
return {id: vfileRoot + 'lib/minpath.browser.js'};
}
if (id === '#minproc') {
return {id: vfileRoot + 'lib/minproc.browser.js'};
}
if (id === '#minurl') {
return {id: vfileRoot + 'lib/minurl.browser.js'};
}
}
return null;
},
};
}
- Add the import
import type {Plugin} from 'vite';then addvfileBrowserPlugin()to thepluginsarray - If
@pack/typesis a dependency inpackage.jsonthen ensure adding@pack/typesto thessr.optimizeDeps.includearray - Add
serverinto root ofdefineConfigbelowoptimizeDeps:
server: {
headers: {
// Allow Private Network Access from public origins (e.g., hosted iframe)
'Access-Control-Allow-Private-Network': 'true',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': '*',
},
allowedHosts: [],
}
Tsconfig Change
Swap all the lines in tsconfig.json with this instead:
{
"include": [
"env.d.ts",
"app/**/*.ts",
"app/**/*.tsx",
"app/**/*.d.ts",
"*.ts",
"*.tsx",
"*.d.ts",
".graphqlrc.ts",
".react-router/types/**/*"
],
"exclude": ["node_modules", "dist", "build", "packages/**/dist/**/*"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"module": "ES2022",
"target": "ES2022",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"baseUrl": ".",
"types": [
"@shopify/oxygen-workers-types",
"react-router",
"@shopify/hydrogen/react-router-types",
"vite/client",
"@types/gtag.js",
"@types/grecaptcha"
],
"paths": {
"~/_": ["app/_"]
},
"noEmit": true,
"rootDirs": [".", "./.react-router/types"],
"incremental": true,
"composite": false,
"verbatimModuleSyntax": true
}
}
ESLint Update
In .eslintrc.cjs
- Remove
@remix-run/eslint-configfrom theextendsarray - Add
importto thepluginsarray - Add
pathGroupsarray in theimport/orderobject (belowgroups):pathGroups: [{pattern: '~/**', group: 'internal'}]
Route Type Pattern Changes
Find all the instances of ActionFunctionArgs, LoaderFunctionArgs, and MetaArgs in the codebase and do the following with the corresponding file:
- Import
Routelike this, where right of the last/is the name of the file itself. For example, if the file name is($locale).products.$handle.tsxthen the import forRoutewould look likeimport type {Route} from './+types/($locale).products.$handle’; - Update
ActionFunctionArgstoRoute.ActionArgs; andLoaderFunctionArgstoRoute.LoaderArgs - Update each
export const metato be:
export const meta: Route.MetaFunction = ({matches}) => {
return (
getSeoMeta(...matches.map((match) => (match?.loaderData as any).seo)) || []
);
};
- Remove the old type imports from the top of the file
Note: Do not make any additional import changes oustide this prompt, that will be handled in a following prompt
Import Updates
- In
entry.client.ts
- Replace the import
import {RemixBrowser} from '@remix-run/react';withimport {HydratedRouter} from 'react-router/dom'; - Replace
<RemixBrowser />with<HydratedRouter />
- In
entry.server.ts
- Replace
import {RemixServer} from '@remix-run/react';withimport {ServerRouter} from 'react-router'; - Replace
import type {EntryContext} from '@shopify/remix-oxygen';withimport type {EntryContext} from 'react-router'; - Replace
import type {AppLoadContext} from '@shopify/remix-oxygen';withimport type {HydrogenRouterContextProvider} from '@shopify/hydrogen'; - Replace the line
remixContext: EntryContextwithreactRouterContext: EntryContext - Replace
<RemixServer context={remixContext} url={request.url} />with<ServerRouter context={reactRouterContext} url={request.url} /> - Replace the line
context: AppLoadContextwithcontext: HydrogenRouterContextProvider
- In
routes.ts
- Replace
import {flatRoutes} from '@remix-run/fs-routes';withimport {flatRoutes} from '@react-router/fs-routes'; - Replace
import type {RouteConfig} from '@remix-run/route-config';withimport type {RouteConfig} from '@react-router/dev/routes'; - Replace
export default hydrogenRoutes([...(await flatRoutes())]) satisfies RouteConfig;with
export default hydrogenRoutes([
...(await flatRoutes()),
// Manual route definitions can be added to this array, in addition to or instead of using the `flatRoutes` file-based routing convention.
// See https://reactrouter.com/api/framework-conventions/routes.ts#routests
]) satisfies RouteConfig;
- Find all instances where components or types are imported from
@shopify/remix-oxygenand change the import to be fromreact-routerinstead
- For example:
import type {AppLoadContext, ActionFunctionArgs} from '@shopify/remix-oxygen';becomesimport type {AppLoadContext, ActionFunctionArgs} from 'react-router'; - This includes
dataandredirect, for example:import {data as dataWithOptions, redirect} from '@shopify/remix-oxygen';becomesimport {data as dataWithOptions, redirect} from 'react-router';
- Find all instances where components or types are imported from
@remix-run/react, and change the import to be fromreact-routerinstead
env.d.ts File
In env.d.ts:
- First if there is no
env.d.tsbut insteadremix.env.d.ts, renameremix.env.d.tstoenv.d.ts - Replace all the
/// <reference />'s at the top with these:
/// <reference types="vite/client" />
/// <reference types="react-router" />
/// <reference types="@shopify/oxygen-workers-types" />
/// <reference types="@shopify/hydrogen/react-router-types" />
- Replace
declare module '@shopify/remix-oxygen'withdeclare module 'react-router'
Remove displayName Definition From All Route Files
For all the app/routes files, if a displayName is defined:
- Replace the
data-compattribute values fromComponentName.displayNameto the actual display name. For example,data-comp={ProductRoute.displayName}becomesdata-comp="ProductRoute" - Remove the
.displayNamedefintion at the bottom
Misc
- If the
DEFAULT_STOREFRONT_API_VERSIONconstant exists, update it to be2025-07; if not, find whereShopifyProvideris rendered, and update the fallback forstorefrontApiVersionto be2025-07 - In
Link.tsx
- Update
RemixLinkto beReactRouterLink; andRemixLinkPropsto beReactRouterLinkProps - Update the comment link to the docs to use the url
https://api.reactrouter.com/v7/functions/react_router.Link.html - Change
remix propertytoreact router property
- Add
.react-routerto.gitignore - Remove
uuidfrompackage.jsonand fromvite.config.tsif it exists; then find all instances whereuuidis being imported, e.g.import {v4 as uuidv4} from 'uuid';, then do the following. At the end runnpm install:
- Replace the use of
uuidv4()withcrypto.randomUUID() - Remove the import from the top
- Find where
useMatchesis being used and change any match using.datato.loaderData - In
useRootLoaderData, update typeRootLoaderDatato be:export type RootLoaderData = Awaited<ReturnType<typeof loader>>;; then remove theSerializeFromimport - In
Scripts.tsx, remove the lineIMPORTANT: Third party scripts rendered directly, i.e. as <script> tags, will likely cause hydration errors as a gotcha of Remix. Use the useLoadScript hook to avoid this issue.if it exists - In
server.ts, change the textCreate a Remix request handlertoCreate a React Router request handler - In
README.md, change any reference toRemixtoReact Router - If
app/lib/admin-api/admin.tsandapp/lib/admin-api/utils/graphql.tsexists, change any reference toRemixtoReact Router
LLM Prompts
Dependency Updates
1. Update or add the following packages accordingly:
- "@shopify/hydrogen": "2025.7.3"
- "@shopify/hydrogen-react": "2025.7.2"
- "@shopify/cli": "^3.88.1" (move to devDependencies)
- "@shopify/cli-hydrogen": "^11.1.6" (move to devDependencies)
- "react-router": "7.12.0"
- "react-router-dom": "7.12.0"
- "@react-router/dev": "7.12.0" (in devDependencies)
- "@react-router/fs-routes": "7.12.0" (in devDependencies)
- "@shopify/mini-oxygen": "^4.0.0" (move to devDependencies)
- "vite": "^6.2.4"
- "@pack/hydrogen": "3.0.0"
- "@pack/react": "4.0.0"
2. Remove following packages:
- "@remix-run/react"
- "@shopify/remix-oxygen"
- "@remix-run/dev"
- "@remix-run/eslint-config"
- "@remix-run/fs-routes"
- "@remix-run/route-config"
3. Update node version to 20, so:
- In `package.json`, change: `"node": ">=18.0.0"` to `"node": ">=20.0.0"`
- In `.nvmrc`, change `v18` to `v20`
4. Delete `node_modules` and `package-lock.json`
5. Run `npm install`
React Router Config File
Add `react-router.config.ts` to the root of the repo:
/* Code starts below. Do not include this line */
import type {Config} from '@react-router/dev/config';
import {hydrogenPreset} from '@shopify/hydrogen/react-router-preset';
/**
* This configuration uses the official Hydrogen preset to provide optimal
* React Router settings for Shopify Oxygen deployment. The preset enables
* validated performance optimizations while ensuring compatibility.
*/
export default {
presets: [hydrogenPreset()],
future: {
// Disable middleware to use legacy context pattern (context.storefront vs context.get())
// This is required until route files are migrated to use context.get(hydrogenContext.*)
v8_middleware: false,
},
} satisfies Config;
/* Code ends above. Do not include this line */
Server.ts Update
In `server.ts`:
1. Replace `import * as remixBuild from 'virtual:remix/server-build';` with `import * as serverBuild from 'virtual:react-router/server-build';`
2. Update the import for `createRequestHandler` and `getStorefrontHeader` to be from `@shopify/hydrogen/oxygen` opposed to `@shopify/remix-oxygen`
3. Replace `build: remixBuild` with `build: serverBuild` within `createRequestHandler`
4. If `testSession` is not being passed into `createPackClient`:
- Import `PackTestSession` from `@pack/hydrogen`
- Fetch `packTestSession`
/* Code starts below. Do not include this line */
const [cache, session, packSession, packTestSession] = await Promise.all([
caches.open('hydrogen'),
AppSession.init(request, [env.SESSION_SECRET]),
PackSession.init(request, [env.SESSION_SECRET]),
PackTestSession.init(request, [env.SESSION_SECRET]),
]);
/* Code ends above. Do not include this line */
- Pass in `packTestSession` as `testSession` to `createPackClient
Vite Config
In `vite.config.ts`
1. Replace `import {vitePlugin as remix} from '@remix-run/dev';` with `import {reactRouter} from '@react-router/dev/vite';`
2. Remove the `remix({...})` plugin from the `plugins` array, and add `reactRouter()` instead
3. Remove any `remix` related dependencies from the `ssr.optimizeDeps.include` and `optimizeDeps.include` arrays, e.g. `@remix-run/dev/server-build`
4. Add `react-router` to the `ssr.optimizeDeps.include` array
5. Add in this `resolve` config to the `ssr` object
/* Code starts below. Do not include this line */
resolve: {
conditions: ['workerd', 'worker', 'browser'],
externalConditions: ['workerd', 'worker'],
},
/* Code ends above. Do not include this line */
6. Add this custom plugin above `export default defineConfig`
/* Code starts below. Do not include this line */
/**
* Plugin to redirect vfile's Node.js imports to browser-compatible versions.
* This fixes "No such module node:path" errors on Oxygen deployment.
*/
function vfileBrowserPlugin(): Plugin {
return {
name: 'vfile-browser',
enforce: 'pre',
resolveId(id, importer) {
// Redirect vfile's internal imports to browser versions
if (importer?.includes('node_modules/vfile/')) {
// Get the vfile package root directory
const vfileRoot = importer.substring(
0,
importer.indexOf('node_modules/vfile/') +
'node_modules/vfile/'.length,
);
if (id === '#minpath') {
return {id: vfileRoot + 'lib/minpath.browser.js'};
}
if (id === '#minproc') {
return {id: vfileRoot + 'lib/minproc.browser.js'};
}
if (id === '#minurl') {
return {id: vfileRoot + 'lib/minurl.browser.js'};
}
}
return null;
},
};
}
/* Code ends above. Do not include this line */
7. Add the import `import type {Plugin} from 'vite';` then add `vfileBrowserPlugin()` to the `plugins` array
8. If `@pack/types` is a dependency in `package.json` then ensure adding `@pack/types` to the `ssr.optimizeDeps.include` array
9. Add `server` into root of `defineConfig` below `optimizeDeps`:
/* Code starts below. Do not include this line */
server: {
headers: {
// Allow Private Network Access from public origins (e.g., hosted iframe)
'Access-Control-Allow-Private-Network': 'true',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': '*',
},
allowedHosts: [],
}
/* Code ends above. Do not include this line */
Tsconfig Change
Swap all the lines in `tsconfig.json` with this instead:
/* Code starts below. Do not include this line */
{
"include": [
"env.d.ts",
"app/**/*.ts",
"app/**/*.tsx",
"app/**/*.d.ts",
"*.ts",
"*.tsx",
"*.d.ts",
".graphqlrc.ts",
".react-router/types/**/*"
],
"exclude": ["node_modules", "dist", "build", "packages/**/dist/**/*"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"module": "ES2022",
"target": "ES2022",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"baseUrl": ".",
"types": [
"@shopify/oxygen-workers-types",
"react-router",
"@shopify/hydrogen/react-router-types",
"vite/client",
"@types/gtag.js",
"@types/grecaptcha"
],
"paths": {
"~/*": ["app/*"]
},
"noEmit": true,
"rootDirs": [".", "./.react-router/types"],
"incremental": true,
"composite": false,
"verbatimModuleSyntax": true
}
}
/* Code ends above. Do not include this line */
ESLint Update
In `.eslintrc.cjs`
1. Remove `@remix-run/eslint-config` from the `extends` array
2. Add `import` to the `plugins` array
3. Add `pathGroups` array in the `import/order` object (below `groups`): `pathGroups: [{pattern: '~/**', group: 'internal'}]`
Route Type Pattern Changes
Find all the instances of `ActionFunctionArgs`, `LoaderFunctionArgs`, and `MetaArgs` in the codebase and do the following with the corresponding file:
1. Import `Route` like this, where right of the last `/` is the name of the file itself. For example, if the file name is `($locale).products.$handle.tsx` then the import for `Route` would look like `import type {Route} from './+types/($locale).products.$handle’;`
- Make sure the route import comes after the `'~/*'` imports with a line in between (i.e. follows eslint import order rule. Same block as sibling imports, i.e. `'./*'`)
2. Update `ActionFunctionArgs` to `Route.ActionArgs`; and `LoaderFunctionArgs` to `Route.LoaderArgs`
3. Update each `export const meta` to be:
/* Code starts below. Do not include this line */
export const meta: Route.MetaFunction = ({matches}) => {
return (
getSeoMeta(...matches.map((match) => (match?.loaderData as any).seo)) || []
);
};
/* Code ends above. Do not include this line */
4. Remove the unused `ActionFunctionArgs`, `LoaderFunctionArgs`, and `MetaArgs` imports from the top of the file
Notes:
1. Do not make any additional import changes oustide this prompt
2. You do not need to ask for permission for every bash command
Import Updates
1. In `entry.client.ts`
- Replace the import `import {RemixBrowser} from '@remix-run/react';` with `import {HydratedRouter} from 'react-router/dom';`
- Replace `<RemixBrowser />` with `<HydratedRouter />`
2. In `entry.server.ts`
- Replace `import {RemixServer} from '@remix-run/react';` with `import {ServerRouter} from 'react-router';`
- Replace `import type {EntryContext} from '@shopify/remix-oxygen';` with `import type {EntryContext} from 'react-router';`
- Replace `import type {AppLoadContext} from '@shopify/remix-oxygen';` with `import type {HydrogenRouterContextProvider} from '@shopify/hydrogen';`
- Replace the line `remixContext: EntryContext` with `reactRouterContext: EntryContext`
- Replace `<RemixServer context={remixContext} url={request.url} />` with `<ServerRouter context={reactRouterContext} url={request.url} />`
- Replace the line `context: AppLoadContext` with `context: HydrogenRouterContextProvider`
3. In `routes.ts`
- Replace `import {flatRoutes} from '@remix-run/fs-routes';` with `import {flatRoutes} from '@react-router/fs-routes';`
- Replace `import type {RouteConfig} from '@remix-run/route-config';` with `import type {RouteConfig} from '@react-router/dev/routes';`
- Replace `export default hydrogenRoutes([...(await flatRoutes())]) satisfies RouteConfig;` with
/* Code starts below. Do not include this line */
export default hydrogenRoutes([
...(await flatRoutes()),
// Manual route definitions can be added to this array, in addition to or instead of using the `flatRoutes` file-based routing convention.
// See https://reactrouter.com/api/framework-conventions/routes.ts#routests
]) satisfies RouteConfig;
/* Code ends above. Do not include this line */
4. Find all instances in the codebase where components or types are imported from `@shopify/remix-oxygen` and change the import to be from `react-router` instead
- For example: `import type {AppLoadContext, ActionFunctionArgs} from '@shopify/remix-oxygen';` becomes `import type {AppLoadContext, ActionFunctionArgs} from 'react-router';`
- This includes `data` and `redirect`, for example: `import {data as dataWithOptions, redirect} from '@shopify/remix-oxygen';` becomes `import {data as dataWithOptions, redirect} from 'react-router';`
5. Find all instances in the codebase where components or types are imported from `@remix-run/react`, and change the import to be from `react-router` instead
Notes:
1. Do not make any additional import changes oustide this prompt
2. You do not need to ask for permission for every bash command
env.d.ts File
In `env.d.ts`:
1. First if there is no `env.d.ts` but instead `remix.env.d.ts`, rename `remix.env.d.ts` to `env.d.ts`
2. Replace all the `/// <reference />`'s at the top with these:
/* Code starts below. Do not include this line */
/// <reference types="vite/client" />
/// <reference types="react-router" />
/// <reference types="@shopify/oxygen-workers-types" />
/// <reference types="@shopify/hydrogen/react-router-types" />
/* Code ends above. Do not include this line */
3. Replace `declare module '@shopify/remix-oxygen'` with `declare module 'react-router'`
Remove displayName Definition From All Route Files
For all the `app/routes` files, if a `displayName` is defined:
- Replace the `data-comp` attribute values from `ComponentName.displayName` to the actual display name. For example, `data-comp={ProductRoute.displayName}` becomes `data-comp="ProductRoute"`
- Remove the `.displayName` defintion at the bottom
Misc
1. If the `DEFAULT_STOREFRONT_API_VERSION` constant exists, update it to be `2025-07`; if not, find where `ShopifyProvider` is rendered, and update the fallback for `storefrontApiVersion` to be `2025-07`
2. In `Link.tsx`
- Update `RemixLink` to be `ReactRouterLink`; and `RemixLinkProps` to be `ReactRouterLinkProps`
- Update the comment link to the docs to use the url `https://api.reactrouter.com/v7/functions/react_router.Link.html`
- Change `remix property` to `react router property`
3. Add `.react-router` to `.gitignore`
4. Remove `uuid` from `package.json` and from `vite.config.ts` if it exists; then find all instances where `uuid` is being imported, e.g. `import {v4 as uuidv4} from 'uuid';`, then do the following. At the end run `npm install`:
- Replace the use of `uuidv4()` with `crypto.randomUUID()`
- Remove the import from the top
5. Find where `useMatches` is being used and change any match using `.data` to `.loaderData`
6. In `useRootLoaderData`, update type `RootLoaderData` to be: `export type RootLoaderData = Awaited<ReturnType<typeof loader>>;`; then remove the `SerializeFrom` import
7. In `Scripts.tsx`, remove the line `IMPORTANT: Third party scripts rendered directly, i.e. as <script> tags, will likely cause hydration errors as a gotcha of Remix. Use the useLoadScript hook to avoid this issue.` if it exists
8. In `server.ts`, change the text `Create a Remix request handler` to `Create a React Router request handler`
9. In `README.md`, change any reference to `Remix` to `React Router`
10. If `app/lib/admin-api/admin.ts` and `app/lib/admin-api/utils/graphql.ts` exists, change any reference to `Remix` to `React Router`
Notes:
1. You do not need to ask for permission for every bash command