✦ Sample Prompt
Migrate every React 17 app to React 19.

For each repository:
1. Update `package.json`:
   - `react` and `react-dom` to `^19.0.0`
   - `@types/react` and `@types/react-dom` to the matching v19 majors
   - Bump compatible peers: `react-router` (6.x+), `@testing-library/react` (16.x+),
     `next` if used (15.x+)
2. Update the root render call:
   - Replace `ReactDOM.render(<App />, root)` with
     `ReactDOM.createRoot(root).render(<App />)`
   - Replace `ReactDOM.hydrate(...)` with `ReactDOM.hydrateRoot(...)`
3. Remove APIs deleted in React 18/19:
   - String refs (`ref="myRef"`) → `useRef`/`createRef`
   - Legacy context (`childContextTypes`, `getChildContext`) → `createContext`
   - `ReactDOM.findDOMNode` → forwarded refs
   - `defaultProps` on function components → ES default parameters
4. Adopt the new JSX transform, remove unused `import React from 'react'`
   statements where the file does not reference `React` directly.
5. Update Suspense/concurrent-affected patterns: wrap data-loading components in
   `<Suspense>` where they use `use()` or new React 19 hooks.
6. Update CI Node version to 20.x (React 19 minimum).

The Problem

Skipping React 18 means absorbing two majors of breaking changes at once. React 18 removed the legacy `ReactDOM.render` API in favour of `createRoot`; React 19 removes string refs, legacy context, `defaultProps` on function components, and `findDOMNode`. The new JSX transform makes most `import React from 'react'` statements obsolete, and TypeScript types tightened in ways that surface latent bugs in component props.

The peer-dependency story is worse than the runtime story. Every UI library, every test library, every routing/data-fetching package needs to be on a React 19-compatible major. `@testing-library/react` 16, `react-router` 6+, `@types/react` 19, `next` 15, each with its own breaking changes. At organizational scale, dozens of frontends with overlapping but non-identical dependency stacks means every repo is a slightly different migration. Doing this one PR at a time across a UI org is months of coordination work.

What Tidra Does

  1. Bumps react, react-dom, and matching @types/* packages to v19 in every package.json
  2. Bumps peer dependencies that have React 19 requirements (react-router, @testing-library/react, next, etc.) to compatible majors
  3. Rewrites root rendering, ReactDOM.rendercreateRoot(...).render(...), ReactDOM.hydratehydrateRoot
  4. Replaces APIs removed in React 18/19, string refs, legacy context, findDOMNode, function-component defaultProps
  5. Strips unused import React from 'react' statements where the file doesn't reference React directly, leveraging the new JSX transform
  6. Updates CI Node version to 20.x (React 19's runtime floor) and re-runs npm test to surface remaining breakages

Before & After

diff
package.json
@@ -8,16 +8,16 @@
"dependencies": {
- "react": "^17.0.2",
- "react-dom": "^17.0.2",
- "react-router-dom": "^5.3.4"
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "react-router-dom": "^6.28.0"
},
"devDependencies": {
- "@types/react": "^17.0.83",
- "@types/react-dom": "^17.0.26",
- "@testing-library/react": "^12.1.5",
- "typescript": "~4.9.5"
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "@testing-library/react": "^16.1.0",
+ "typescript": "~5.6.0"
},
- "engines": { "node": ">=16" }
+ "engines": { "node": ">=20" }
}

Customization Tips

  • Skip via 18 or direct: Going 17 → 19 in one PR is faster but riskier. For large apps, consider a 17 → 18 stop first to isolate the createRoot switch from the API removals.
  • Strict mode: React 19 strict mode double-invokes effects in development. Apps that have been quietly relying on single-invoke behaviour will need effect cleanups audited.
  • Component library compatibility: Confirm your design system (MUI, Chakra, Ant Design, etc.) has a React 19-compatible release before bulk-migrating consumer apps. Pinning to RC versions causes churn.
  • Test coverage gate: Require npm test and a production build per repo before merging. Type errors from the React 19 @types updates often only surface at build time.

Ready to run this across your repos?

Connect your Git provider and Tidra opens pull requests in every repo that needs them.