React 19 shipped in April 2024 and became the widely-adopted default through 2025-2026. If your app is still on React 18, you are missing new hooks (useActionState, use, useOptimistic), the Actions API, better Server Components support, and a batch of small quality-of-life improvements. This 2026 migration guide walks you through the actual differences, the breaking changes that trip most teams, and a step-by-step plan for moving a real React 18 codebase to React 19.
Quick 2026 verdict
The React 18 to 19 upgrade is one of the smoother React major-version bumps. Most existing code compiles unchanged. The four things that break the most projects: PropTypes removal, defaultProps removal on function components, legacy Context API removal, and string refs removal. The upside: cleaner Server Component patterns, the new use hook for consuming promises, and Actions for handling form state. Migration takes 2-8 hours for a medium codebase.
What changed between React 18 and React 19
The high-level shifts:
- New hooks:
use,useActionState,useOptimistic,useFormStatus. - Actions API: form handling and mutation logic that integrates with Server Components + React Server Actions (in Next.js and other RSC frameworks).
- Ref as a prop: you can now pass
refas a normal prop;forwardRefis no longer needed for most cases. - Document metadata support: render
<title>,<meta>,<link>inside your components and React hoists them to<head>. No more react-helmet. - Removed: PropTypes, defaultProps on function components, string refs, legacy Context API (createContext still works), React.createFactory.
- Better error messages: React 19 gives clearer stack traces and warning hydration errors.
The new hooks explained (with examples)
use hook: consume a promise or context inside a component.
import { use } from 'react';
function UserProfile({ userPromise }) {
const user = use(userPromise); // suspends until the promise resolves
return <h1>{user.name}</h1>;
}Wrap the component in <Suspense fallback=...> and React handles the loading state automatically. Replaces most patterns that used useEffect + useState + loading + error.
useActionState: form state + async action + optimistic pending in one hook.
import { useActionState } from 'react';
async function submitAction(prevState, formData) {
const name = formData.get('name');
await saveUser(name);
return { message: 'Saved!' };
}
function Form() {
const [state, action, isPending] = useActionState(submitAction, { message: '' });
return (
<form action={action}>
<input name="name" />
<button disabled={isPending}>{isPending ? 'Saving...' : 'Save'}</button>
<p>{state.message}</p>
</form>
);
}useOptimistic: show an optimistic UI while the async action runs.
import { useOptimistic } from 'react';
function ChatWindow({ messages, sendMessage }) {
const [optimisticMessages, addOptimistic] = useOptimistic(messages, (current, newMsg) => [...current, newMsg]);
async function handleSend(text) {
addOptimistic({ id: Date.now(), text, pending: true });
await sendMessage(text);
}
return optimisticMessages.map(m => <div key={m.id}>{m.text}</div>);
}The breaking changes that will bite you
1. PropTypes removed from the react package. If you still use propTypes:
// React 18
import PropTypes from 'prop-types';
MyComponent.propTypes = { name: PropTypes.string };
// React 19
// Delete propTypes entirely (recommended)
// OR install prop-types package separately if you must keep them:
// npm install prop-typesMigration: switch to TypeScript (recommended long-term) or add prop-types as an explicit dependency.
2. defaultProps removed from function components.
// React 18
function Greeting({ name }) { return <h1>Hi {name}</h1>; }
Greeting.defaultProps = { name: 'Guest' };
// React 19: use default parameter destructuring instead
function Greeting({ name = 'Guest' }) { return <h1>Hi {name}</h1>; }Class components still support defaultProps; only function components lost it.
3. String refs removed. <input ref="myRef" /> no longer works. Use useRef or callback refs.
4. Legacy Context API removed. The old contextTypes + childContextTypes pattern is gone. If your codebase still uses this (rare, but possible in older code), migrate to modern createContext + useContext.
Ref as a prop (no more forwardRef for most cases)
// React 18: had to wrap in forwardRef
const Input = forwardRef(function Input(props, ref) {
return <input ref={ref} {...props} />;
});
// React 19: ref is just a prop
function Input({ ref, ...props }) {
return <input ref={ref} {...props} />;
}Existing forwardRef code still works; you just do not need it for new components.
Document metadata support
Render metadata tags anywhere in your component tree and React hoists them to <head>:
function BlogPost({ title, description }) {
return (
<article>
<title>{title}</title>
<meta name="description" content={description} />
<h1>{title}</h1>
<p>{description}</p>
</article>
);
}react-helmet and next/head are still around but often unnecessary now. In Next.js App Router, the metadata export in page.tsx and layout.tsx is still the recommended API for SEO metadata; the React 19 approach is best for dynamic per-component metadata.
Step-by-step migration plan
- Update React and React DOM.
npm install react@19 react-dom@19. If you use Next.js, update to Next.js 15 which requires React 19. TypeScript types come via@types/react@19and@types/react-dom@19. - Run the codemod.
npx types-react-codemod@latest preset-19 ./srcfixes most TypeScript type issues automatically. - Search for PropTypes usage. Grep your codebase:
grep -r "propTypes" src/. Remove or install prop-types package. - Search for defaultProps on function components. Grep:
grep -r "defaultProps" src/. Convert function component ones to default parameters. - Search for string refs. Grep:
grep -rn 'ref="' src/. Rewrite asuseRefor callback refs. - Run the test suite. Most failures are TypeScript type mismatches at this point, all fixable in minutes.
- Check hydration. React 19 catches more hydration mismatches. If your SSR app now shows hydration warnings, they were probably silent bugs before. Fix each one.
- Progressive adoption of new hooks. No need to rewrite everything. Adopt
use,useActionState, anduseOptimisticin new features. Old code withuseState + useEffectkeeps working.
Common migration gotchas in 2026
- Third-party libraries with old peer dependencies. Some libraries pin to React 18 in
peerDependencies. Check withnpm ls react. Most maintainers updated in 2024-2025; a few stragglers may need--legacy-peer-depsduring install. - Redux + React 19. Redux Toolkit v2 and above are compatible with React 19. Older Redux setups need
react-redux@9+. - Testing libraries. React Testing Library 16+ and Jest 29+ work with React 19. Enzyme is unmaintained since 2020 and does not support React 19.
- Concurrent mode side effects. React 19 runs effects more aggressively in dev mode (StrictMode double-invokes). This surfaces old bugs where effects assumed they would only run once.
- Legacy class components. Still supported but Meta’s team clearly signals class components are the past. If you have time, convert to function components during the upgrade for a cleaner codebase going forward.
Frequently Asked Questions
How long does React 18 to 19 migration take?
2-8 hours for a medium codebase (50-200 components), assuming you already use TypeScript and have a working test suite. The codemod handles most type issues automatically. Small apps under 20 components can migrate in under an hour. Very large enterprise codebases with legacy patterns can take 2-3 days.
Do I have to rewrite my code to use the new hooks?
No. useState, useEffect, useContext all still work identically. Adopt useActionState, useOptimistic, and use progressively in new features. Rewriting stable code just to use new hooks adds risk without benefit.
Is React 19 backwards compatible?
Mostly yes. The four removals (PropTypes, defaultProps on function components, string refs, legacy Context) are the main breakage points. Everything else is additive. If your codebase is TypeScript-first without those legacy patterns, you may find zero code changes needed beyond bumping the version.
What about React Native?
React Native has its own release cadence tied to Meta’s mobile teams. React 19 features flow into React Native at a delay of 3-6 months. The core hooks (useState, useEffect) are always compatible; the Server Components + Actions APIs are still web-first in 2026.
Do Server Components require React 19?
The proper support does. React 18 shipped a preview version of Server Components but the full APIs (async Server Components, use hook consuming server-fetched promises, Actions) require React 19. Next.js 15 required the React 19 upgrade for full RSC support.
What is the “React 20” outlook?
Meta has not committed to a React 20 release date as of Sep 2026. React’s release cadence has slowed since concurrent mode landed. Any React 20 is likely to be small-breaking-change and additive, with a codemod path. No reason to wait on 19 for a hypothetical 20.
Related Modern Web Dev tutorials
- Next.js 15 Complete Beginner Guide 2026 (First App)
- TypeScript Complete Beginner Tutorial 2026 (coming this week)
- Server Components vs Client Components 2026 (coming this week)
- Astro vs Next.js vs Nuxt 2026 Comparison (coming this week)
