React 19 shipped stable in December 2024 and landed with unusual fanfare — the React team had been signaling Server Components for two years and the wait was charged. Now, 18 months later, the ecosystem dust has settled: the frameworks have caught up, the adoption patterns are clear, and the parts that were genuinely good have separated from the parts that were more aspirational. This is the guide for developers who want to know what to actually use now.
What React 19 changed
Four additions define the release:
1. Actions and useTransition for async mutations
The old pattern for a form mutation: useState for loading, useState for error, try/catch around fetch, manual pending state reset. Dozens of lines for something every app does constantly.
React 19's Actions pattern wraps async functions and gives you isPending, error, and the result — handled automatically. Combined with useTransition, you get non-blocking UI updates during async work without any manual state management:
function UpdateUsername() {
const [error, submitAction, isPending] = useActionState(
async (prev, formData) => {
const error = await updateUsername(formData.get('name'));
return error;
},
null
);
return (
<form action={submitAction}>
<input name="name" />
<button disabled={isPending}>{isPending ? 'Saving…' : 'Save'}</button>
{error && <p>{error}</p>}
</form>
);
}
This pattern alone justifies upgrading. It eliminates a category of boilerplate that existed in nearly every React app.
2. Server Components stable
React Server Components (RSC) let you run component rendering on the server — accessing databases, filesystems, or APIs directly in the component, with zero client-side JS bundle cost for the server-rendered output. Client interactivity is added via 'use client' boundary components.
The critical caveat in 2026: RSC requires a framework. Next.js App Router (v15) and Remix (v3) both support them. Raw React + Vite does not. The mental model shift is also real: you need to think carefully about which components are server vs client and how data flows across the boundary.
For new projects on Next.js, RSC is the right default. For existing applications, the migration cost is high enough that it's rarely worth retrofitting.
3. The use() hook
use() is a new primitive that can read a Promise or Context value inside a component's render function — something that previously required either useEffect + state or a Suspense boundary with a library like React Query.
function UserProfile({ userPromise }) {
const user = use(userPromise); // Suspends until resolved
return <p>{user.name}</p>;
}
Combined with Suspense, this gives you clean async data fetching in components without effect boilerplate. It works in both client and server components, making it the recommended pattern for resource loading in 2026.
4. ref as a prop
Refs can now be passed as regular props instead of requiring forwardRef. This eliminates a significant friction point for component library authors. Small change, broad impact across codebases that heavily use refs.
Comparison: React 18 vs React 19
| Feature |
React 18 |
React 19 |
Adoption complexity |
| Async mutations |
Manual useState + try/catch |
useActionState + Actions |
Low — drop-in for most forms |
| Server Components |
Experimental |
Stable (framework-required) |
High — requires RSC-aware framework |
| Data fetching in render |
useEffect + state or React Query |
use() + Suspense |
Medium — different mental model |
| Form handling |
Controlled/uncontrolled components |
Native form Actions |
Low — opt-in |
| Ref passing |
forwardRef required |
Prop (no forwardRef) |
Low — backwards compatible |
| Concurrent features |
On |
On (same) |
None |
What still needs a framework
Despite "stable" RSC, you cannot use Server Components in a Vite + React app without additional infrastructure. The render-on-server-send-to-client pipeline requires a custom server setup or a framework that handles it. In 2026, that means:
- Next.js 15 App Router — full RSC support, streaming, server actions
- Remix 3 — RSC support, loader-based data pattern
- Waku — lightweight RSC-first framework from the Jotai team
Everything else (Vite, Create React App, Parcel) does not support RSC without significant custom work. This is not a React bug — it's an architectural requirement.
Common migration gotchas
useEffect cleanup warnings. React 19 is stricter about double-invocation in Strict Mode. Effects that weren't properly cleaning up will surface errors that were previously silent.
Library compatibility. Some React 18-era UI libraries haven't fully updated for 19's ref-as-prop changes. Check your key dependencies before upgrading in production.
forwardRef is deprecated but not removed. It still works; you just get a deprecation warning. Migrate incrementally.
Server/client boundary errors are runtime, not compile-time. Using useState in a Server Component doesn't fail during build — it fails at runtime. TypeScript won't catch it. Add RSC-specific linting rules (eslint-plugin-react-server-components) early.
FAQ
Should I migrate my React 18 app to React 19 today?
Yes for the package upgrade (it's backwards compatible for most apps). No for RSC migration — only do that if you're on Next.js and have a concrete performance or data-fetching problem that RSC addresses.
Does React 19 require TypeScript?
No — but the new features (especially Actions) have good TypeScript inference and the types are well-maintained. You'll have a better time with TS.
Is React Query obsolete with use() and Server Components?
Not yet. React Query still handles caching, deduplication, background refetching, and client-side mutation state in ways that use() doesn't. The overlap is real but the use cases are different.
Where to go next
For more frontend engineering guidance see best React frameworks in 2026, best React UI libraries in 2026, and best React state management in 2026.