Installing npm react router dom the right way comes down to one rule: only React Router v5 and earlier need @types/react-router-dom, while v6 and v7 ship their own TypeScript types and the separate types package will actively fight you. A surprising number of broken builds, phantom type errors, and bloated dependency trees trace back to teams carrying a stale @types/react-router-dom entry into a v6 or v7 upgrade. This guide walks through the version history, the correct install for each major version, and the dependency hygiene that keeps a router upgrade from becoming a security review item.
The three eras of react-router-dom
React Router has shipped three meaningfully different APIs in the past few years:
- v5 (2019 era): class-friendly API,
Switch,withRouter, and no bundled types. TypeScript users installed@types/react-router-domfrom DefinitelyTyped, which peaked at version 5.3.x. - v6 (2021): hooks-first rewrite with
RoutesreplacingSwitch. The package ships its own type definitions, so the DefinitelyTyped package became unnecessary. - v7 (released November 22, 2024): React Router and Remix merged. The core package is now
react-router, with DOM APIs collapsed intoreact-router/dom. To ease upgrades, everything is still re-exported throughreact-router-domin v7, and the project added a type generator that produces strongly typed route modules, loaders, and params.
Knowing which era you are in decides everything about the install.
Correct installs per major version
For a v5 codebase:
npm install react-router-dom@5
npm install --save-dev @types/react-router-dom@5
For v6:
npm install react-router-dom@6
npm uninstall @types/react-router-dom
For v7, the recommended dependency is the core package:
npm install react-router@7
You can keep importing from react-router-dom during a v6 to v7 migration since v7 re-exports through it, but new code should import from react-router directly, because the plan of record drops react-router-dom in v8.
The uninstall step for v6 and v7 is not optional cleanup. When the stale types package sits next to a version that bundles its own types, the compiler can resolve two conflicting declaration sets. The result is confusing errors about useNavigate or RouteProps not existing, which developers sometimes "fix" by pinning the router backwards instead of removing the types package.
Why types react router dom searches spike after upgrades
If you search for types react router dom errors, most hits are upgrade casualties. The failure pattern is consistent: a team bumps react-router-dom from 5.x to 6.x in package.json, npm keeps @types/react-router-dom@5.3.x because nothing asked for its removal, and the type surface of v5 shadows the real v6 exports. TypeScript then reports that Routes does not exist, or infers any where it should infer route params.
The check takes ten seconds:
npm ls react-router-dom @types/react-router-dom
If the second package appears at all in a v6 or v7 project, remove it. While you are there, confirm nothing else pins it transitively; component libraries written in the v5 era occasionally declared it as a real dependency instead of a dev dependency.
The npm react dom confusion
One adjacent trap: people searching for npm react dom often conflate three distinct packages. react-dom is React's renderer and is a peer dependency of your entire app. react-router-dom is the routing library. @types/react-router-dom is types-only and version-locked to v5. Mixing up the first two in a package.json audit is rare, but automated dependency update tools have been known to propose "upgrades" grouping them together, and rubber-stamping such a PR can jump you across a breaking router major without anyone reading the changelog.
Treat router majors like framework migrations, not patch bumps. Review the diff of any bot PR that touches react-router-dom npm entries, and never let a grouped update PR mix router majors with routine patch updates.
Dependency hygiene and the supply chain angle
Routing libraries sit on a sensitive path: they parse URLs, drive redirects, and often gate authenticated layouts. That makes their dependency hygiene worth more attention than a color-picker widget gets:
- Pin through a lockfile and commit it. A floating
^6.0.0range without a lockfile means CI can silently pick up a new minor the day it publishes. Our guide on npm lockfile security covers the failure modes. - Watch for abandoned type stubs. DefinitelyTyped packages stop receiving updates when upstream bundles types. A types package frozen in 2021 is not vulnerable by itself, but it signals a dependency tree nobody has audited recently.
- Scan the whole tree, not the top level. Older UI kits can drag in v5-era router copies transitively, leaving two router versions in one bundle. A software composition analysis tool like Safeguard's SCA will surface duplicate majors and flag the stale lineage even when
package.jsonlooks clean.
Duplicate router versions are not just bundle bloat. Two routers means two URL parsers with subtly different semantics, and redirect handling that behaves differently depending on which copy a component resolved. Security reviews of open-redirect bugs regularly find this exact setup underneath.
Upgrade path that will not surprise you
A sane migration sequence from v5 to v7:
- Upgrade v5 to the latest 5.3.x patch and get the app green.
- Enable the v5 future flags, then move to v6 following the official migration guide. Remove
@types/react-router-domin the same commit you bump the major, so the failure surface is one reviewable change. - On v6, adopt the data APIs (
createBrowserRouter) incrementally. - Move to v7 by switching installs to
react-router, enabling future flags first. v7 requires modern React and Node versions, so check your runtime matrix before the bump.
Run your integration tests against redirect and auth-gating flows at every step. Router upgrades are where "the tests passed" and "logged-out users can see the dashboard shell" have been known to coexist. If you want a structured refresher on securing React apps around the router, the Safeguard Academy has hands-on material, and our React security best practices post covers the framework-level pitfalls.
FAQ
Do I need @types/react-router-dom with React Router v6?
No. React Router v6 and v7 ship their own TypeScript definitions. Installing @types/react-router-dom alongside v6 or v7 causes conflicting declarations and misleading compile errors. The types package is only correct for v5 and earlier.
Which package do I install for React Router v7?
Install react-router. The v7 release re-exports everything through react-router-dom for backward compatibility, but the DOM entry point is now react-router/dom and the standalone react-router-dom package is planned for removal in v8.
Is an old react-router-dom version a security risk?
Age alone is not a vulnerability, but stale majors correlate with unaudited trees, duplicate transitive router copies, and abandoned type stubs. Routing code handles redirects and auth boundaries, so keep it on a supported major and scan transitively.
Why does npm still show @types/react-router-dom updates?
DefinitelyTyped kept the package current for the v5 line, which is why its versions stop at 5.x. There will never be a 6.x or 7.x of the types package, because upstream bundles types now.