> **TL;DR.** React 19 ships Server Components, a new Actions model, the `use()` hook, and an opt-in compiler that eliminates most manual memoization. If you're building a greenfield app in 2026, these features change how you structure data fetching, mutations, and state. This guide covers what's new, what it replaces, and how to migrate without breaking your existing code.
---
What Actually Changed in React 19
React 19 is not a cosmetic release. It restructures three core concerns: where components render, how mutations happen, and how the runtime handles re-renders.
**Before React 19**, the standard approach was:
- Fetch data in `useEffect` or a data-fetching library like React Query
- Handle form submissions with `useState` + `onChange` + manual loading/error states
- Prevent unnecessary re-renders with `useMemo`, `useCallback`, and `React.memo`
**With the react 19 complete feature set**:
- Server Components run on the server at request time, never ship their code to the browser
- Actions handle async mutations with built-in pending/error states
- The React Compiler eliminates memoization boilerplate automatically
- `use()` lets you read Promises and Context mid-render without a dedicated hook
These aren't incremental improvements — they change where the interesting logic lives.
---
Server Components: What They Are and When to Use Them
Server Components render on the server and send HTML (plus a serialized component tree) to the client. They have zero JavaScript bundle impact and can directly query databases, read files, or call internal APIs.
**Key constraints:**
- No `useState`, `useEffect`, or browser APIs
- Cannot attach event handlers directly
- Must explicitly mark interactive children as `"use client"`
**What this means in practice:**
```jsx
// app/products/page.tsx — Server Component (no "use client")
export default async function ProductsPage() {
const products = await db.query('SELECT * FROM products LIMIT 50');
return <ProductList products={products} />;
}
```
```jsx
// components/ProductList.tsx
"use client";
export function ProductList({ products }) {
const [filter, setFilter] = useState('');
// interactive logic here
}
```
The boundary between server and client is explicit at the file level. The server component does the data work; the client component handles interaction.
**When Server Components are the wrong choice:**
- Small SPAs where SSR complexity isn't worth it
- Apps that need deeply interactive, real-time UIs (rich text editors, collaborative tools)
- Teams not using a framework that supports RSC (Vite alone doesn't; Next.js 14+ does)
---
Actions: Replacing the Old Mutation Pattern
Actions are async functions you pass to form elements or trigger imperatively. React handles pending state, errors, and optimistic updates for you.
**Old pattern:**
```jsx
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
try {
await submitForm(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
```
**React 19 Actions:**
```jsx
async function createPost(formData) {
"use server"; // marks this as a Server Action
await db.posts.create({ title: formData.get('title') });
revalidatePath('/posts');
}
export function PostForm() {
return (
<form action={createPost}>
<input name="title" />
<SubmitButton />
</form>
);
}
```
`useFormStatus()` inside `SubmitButton` gives you `pending` without prop-drilling. `useActionState()` gives you the last return value from the action and the current pending state in one hook.
For client-side mutations, you can pass a regular async function to `action` — it doesn't have to be a Server Action.
---
New Hooks Reference
**`useOptimistic` example:**
```jsx
function LikeButton({ postId, initialCount }) {
const [optimisticCount, addOptimistic] = useOptimistic(
initialCount,
(current, increment) => current + increment
);
async function handleLike() {
addOptimistic(1);
await likePost(postId);
}
return <button onClick={handleLike}>{optimisticCount} likes</button>;
}
```
The UI updates instantly. If the server call fails, React rolls back to `initialCount`.
---
The React Compiler
React Compiler (previously called "React Forget") is an opt-in Babel/SWC plugin that analyzes your components at build time and inserts memoization automatically. In most codebases this means you can delete:
- `useMemo` for derived values
- `useCallback` for stable function references
- `React.memo` on most components
**To enable in Next.js 15+:**
```js
// next.config.js
module.exports = {
experimental: {
reactCompiler: true,
},
};
```
**Caveats:**
- The compiler works correctly only when your code follows the Rules of React (no mutation of props, no side effects in render). Violating these rules silently before is now a correctness problem, not just a style problem.
- Run `react-compiler-healthcheck` before enabling on a large codebase to see what percentage of components it can optimize.
- It doesn't replace `useMemo` for genuinely expensive computations — it optimizes re-render skipping, not computation cost.
---
Framework Support in 2026
**Next.js (App Router)** is the primary first-class environment for the react 19 complete feature set. Server Components, Server Actions, and streaming are built into the framework. If you're starting fresh, App Router + Next.js 15 is the default choice.
**Remix v3** adopted the React 19 model with its own loader/action primitives. The mental model is similar but data fetching stays in route-level loaders rather than Server Components.
**Astro** uses React as an island framework. You get client-side React 19 features but not Server Components — Astro handles server rendering its own way.
**Vite + React (SPA)** gets `use()`, Actions (client-side), the compiler, and the new hooks — but not Server Components or Server Actions. For SPAs this is still a meaningful upgrade over React 18.
For framework comparisons, see [React vs Vue vs Svelte 2026](/en/rehberler/react-vs-vue-vs-svelte-2026).
---
Migrating from React 18 to 19
React 19 ships with breaking changes. The upgrade path is documented, but here's what catches people:
**1. `ReactDOM.render` is removed** (was deprecated in 18). Migrate to `createRoot`:
```js
// Before
ReactDOM.render(<App />, document.getElementById('root'));
// After
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
```
**2. String refs are removed.** Use `useRef` or `createRef`.
**3. `defaultProps` on function components is deprecated.** Use ES6 default parameters.
**4. `act()` warnings in tests.** React 19 is stricter about wrapping state updates in `act()`. Most Testing Library versions handle this automatically.
**5. Context API provider syntax change:**
```jsx
// React 18
<ThemeContext.Provider value={theme}>
// React 19 (both work, but new shorthand is preferred)
<ThemeContext value={theme}>
```
**Migration checklist:**
1. Upgrade to React 18.3 first (it adds deprecation warnings for everything React 19 removes)
2. Fix all warnings before bumping to 19
3. Run your test suite — `act()` changes surface quickly
4. Enable the compiler incrementally on a per-file basis (`"use no memo"` opt-out)
---
React 19 and AI-Assisted Development
The new patterns interact well with AI coding tools. Server Actions in particular are easy to generate correctly because they're pure async functions with a known signature. When using tools like Cursor or Claude Code, prompting for "a Server Action that does X" produces reliable, reviewable code.
The compiler also reduces the surface area for AI-generated bugs: most memoization errors disappear when the compiler handles it, so generated components that forget `useCallback` still work correctly.
For a workflow that combines React 19 with AI tooling end-to-end, see [AI for Fullstack Devs 2026](/en/rehberler/ai-fullstack-devs-2026) and [How to Use Cursor 2026](/en/rehberler/how-to-use-cursor-2026).
---
Next Steps
- **Upgrade path:** Start with React 18.3, clear all deprecation warnings, then bump to 19.
- **New project:** Next.js 15 App Router gives you the complete Server Components + Actions experience out of the box.
- **Compiler adoption:** Run `react-compiler-healthcheck` on your repo before enabling globally.
- **Team knowledge:** The mental model shift (server/client boundary, Actions replacing mutation patterns) is the hardest part — prioritize that over syntax.
- **Framework choice:** If you're evaluating alternatives, [React vs Vue vs Svelte 2026](/en/rehberler/react-vs-vue-vs-svelte-2026) covers the current tradeoffs.