Step-by-step migration from React Router v7 to TanStack Router: route definition conversion, Link/useNavigate API differences, useSearchParams to validateSearch + useSearch, useParams with from, Outlet replacement, loader conversion, code splitting differences.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
This is a step-by-step migration checklist. Each check covers one conversion task. Complete them in order.
CRITICAL: If your UI is blank after migration, open the console. Errors like "cannot use useNavigate outside of context" mean React Router imports remain alongside TanStack Router imports. Uninstall react-router (and react-router-dom if present) to surface them as TypeScript errors.
CRITICAL: TanStack Router uses to + params for navigation, NOT template literal paths. Never interpolate params into the to string.
NOTE: React Router v7 recommends importing from react-router (not react-router-dom). The react-router-dom package still exists but just re-exports from react-router. Check for imports from both.
React Router's useLocation is heavily used, and TanStack Router has a hook with the same name โ but they are NOT equivalent. TanStack Router's useLocation() returns the router's current location, which during pending navigations may differ from what's currently rendered. Most React Router useLocation usage should be replaced with more specific hooks. See #3110.
Replace based on what you actually need:
// React Routerimport { useLocation } from'react-router'const location = useLocation()
// โ DON'T just swap to TanStack Router's useLocation โ it's the "live" URLimport { useLocation } from'@tanstack/react-router'// โ DO use the specific hook for what you need:import {
useMatch,
useMatches,
useParams,
useSearch,
} from'@tanstack/react-router'// Current route match (replaces most useLocation().pathname usage)const match = useMatch({ from: '/posts/$postId' })
// All active matches (replaces useLocation for breadcrumbs/analytics)const matches = useMatches()
// Path params (replaces useLocation + manual parsing)const { postId } = useParams({ from: '/posts/$postId' })
// Search params (replaces useLocation().search parsing)const { page } = useSearch({ from: '/posts' })
Outlet
Replace React Router Outlet with TanStack Router Outlet
Both libraries export Link, useNavigate, Outlet, etc. Leftover React Router imports cause "cannot use useNavigate outside of context" errors because the wrong context provider is used.
// WRONG โ mixed importsimport { Link } from'@tanstack/react-router'import { useNavigate } from'react-router'// <- still React Router!// CORRECT โ all from TanStack Routerimport { Link, useNavigate } from'@tanstack/react-router'
Fix: Uninstall react-router/react-router-dom completely. TypeScript will flag every stale import.
2. HIGH: Using React Router useSearchParams pattern