Why are we still writing API routes in 2026? It is a question that would have sounded absurd a few years ago, but React 19 and Next.js 15+ have fundamentally disrupted the traditional client-server boundary. With the stabilization of React Server Components (RSC) and Server Actions, the industry is witnessing a massive architectural shift. The core debate has crystallized into a direct comparison: server actions vs trpc.
For years, tRPC was the undisputed champion of end-to-end type safety in the TypeScript ecosystem. It eliminated the boilerplate of REST and GraphQL by sharing types directly between your backend router and your frontend client. However, now that React 19 compiles server-side functions directly into RPC endpoints, developers are questioning whether they need an external API library at all. In this comprehensive guide, we will analyze react 19 server actions vs trpc to help you choose the best API architecture for your next enterprise application.
The Architectural Divide: How React 19 Server Actions and tRPC Work
To make an informed decision, we must first understand the fundamental differences in how these two technologies handle network requests. They may both provide end-to-end type safety, but their execution models and underlying engines are entirely different.
+-------------------------------------------------------------------------+
| CLIENT BOUNDARY |
| |
| [ React 19 Client Component ] <---+ |
| | | |
| (Server Action Call) (RSC Wire Format) |
| | | |
| v | |
+----------------|--------------------|-----------------------------------+
| |
| (HTTP POST) |
v |
+----------------|--------------------|-----------------------------------+
| v | |
| [ React 19 Server Runtime ] ------+ |
| | |
| (Direct DB Query) |
| | |
| v |
| [ Database / ORM ] |
| |
| SERVER BOUNDARY |
+-------------------------------------------------------------------------+
What is tRPC?
tRPC is a build-time and runtime tool that allows you to share TypeScript types directly from your backend router to your frontend client. It works by creating a single, centralized router on your server.
When you write a query or mutation in tRPC, you define a schema (usually using Zod, Valibot, or ArkType) to validate the input. On the client, you import the type of your router—not the actual runtime code—and use a client library (often integrated with TanStack Query) to make requests. The network layer is standard HTTP (typically JSON-RPC-like), and the client handles all the fetching, loading states, and caching.
What are React 19 Server Actions?
Server Actions are a native React 19 feature designed to execute server-side code without requiring you to manually define an API route. Instead of setting up a separate router, you annotate an asynchronous function with the 'use server' directive.
When the React compiler encounters this directive, it splits the code. The client bundle receives an opaque, hashed URL string that points to an auto-generated endpoint. When the client calls this function, React automatically performs an HTTP POST request behind the scenes, executes the function in a secure server-side environment (like Node.js or a Cloudflare Worker), and returns the serialized result.
Senior Engineer Insight: "It is helpful to think of Server Actions as React-managed RPCs. You are not importing a function; you are importing a reference to an endpoint that React dynamically provisions and manages during the build process. This completely bypasses the need for manual API route configuration."
Is tRPC Dead in 2026? Sifting Hype From Production Reality
With the release of React 19, a common sentiment has echoed through Reddit and Twitter: is trpc dead 2026? If the framework handles the API layer automatically, why bother adding another library to your stack?
The short answer is no, tRPC is not dead. However, its target use case has narrowed significantly. To understand why, we have to look at where Server Actions fail and where tRPC continues to excel.
The Case Against Server Actions for Complex Apps
While Server Actions are incredibly convenient for simple mutations, they introduce several architectural challenges when scaled to enterprise-grade applications:
- The Serial Execution Bottleneck: By default, Server Actions in Next.js run sequentially. If you trigger multiple Server Actions simultaneously, the server processes them one after another to maintain predictable state revalidation. For highly dynamic dashboards that need to make multiple parallel network requests, this is a massive performance bottleneck.
- The Single-Client Lock-in: Server Actions are highly coupled to your React build. The auto-generated endpoints use unique, build-specific hashes. This means you cannot call a Server Action from a mobile app (like React Native/Expo), a public API, a third-party webhook, or an external microservice. If you are building a multi-client ecosystem, you still need a standard API layer.
- Granular UI Control: tRPC integrates deeply with TanStack Query, offering robust client-side state management, cache invalidation, infinite scrolling, refetch-on-window-focus, and request deduplication. Server Actions lack these client-side primitives out of the box.
Why tRPC Remains Relevant in 2026
tRPC remains a dominant choice for teams building multi-client applications or highly dynamic, client-heavy dashboards.
If you have a dedicated backend team managing an Express, Fastify, or NestJS server, tRPC allows you to maintain end-to-end type safety across separate repositories without forcing the backend into a React-specific paradigm. It acts as an evolutionary step away from REST, whereas Server Actions are a complete paradigm shift toward server-client unification.
Type Safety Showdown: Next.js Server Actions Type Safety vs tRPC Contracts
Type safety is the primary reason developers choose these architectures. Let's compare how nextjs server actions type safety holds up against tRPC's robust contract-based model.
Raw Server Actions: The Type Safety Illusion
Out of the box, raw Server Actions are not as type-safe as they appear. Consider this common pattern for a form submission:
typescript // actions.ts 'use server';
export async function updateProfile(formData: FormData) { const name = formData.get('name') as string; // Manual type casting! const email = formData.get('email') as string;
// Database write... }
Because HTML forms natively submit FormData, you are forced to manually extract and cast variables on the server. There is no runtime validation ensuring that name is actually a string or that email matches a valid email format. If a user bypasses your client-side validation and sends a malformed payload, your server code will crash.
To make Server Actions safe, you have to write a mountain of boilerplate:
typescript // Raw but safe server action 'use server'; import { z } from 'zod';
const schema = z.object({ name: z.string().min(3), email: z.string().email(), });
export async function updateProfile(rawData: unknown) { const validated = schema.safeParse(rawData); if (!validated.success) { return { error: validated.error.flatten() }; }
// Database write... }
The tRPC Approach: Strict Input Contracts
tRPC solves this elegantly by forcing you to define input schemas at the router level. The type safety is enforced both at compile-time and runtime:
typescript // trpcRouter.ts import { publicProcedure, router } from './trpc'; import { z } from 'zod';
export const appRouter = router({ updateProfile: publicProcedure .input(z.object({ name: z.string().min(3), email: z.string().email(), })) .mutation(async ({ input }) => { // input is fully typed as { name: string; email: string } return { success: true }; }), });
On the client, tRPC ensures that you cannot call updateProfile without passing the exact object structure required by the Zod schema. If you rename a field in your schema, TypeScript will immediately flag errors across your entire frontend codebase. This provides a seamless developer experience that raw Server Actions cannot match without third-party libraries.
Performance and Execution: Caching, Revalidation, and the Serial Bottleneck
When evaluating server actions vs trpc, performance is often the deciding factor. The two architectures handle data fetching, caching, and state transitions in fundamentally different ways.
React Server Components and Server Actions: The Revalidation Loop
One of the biggest advantages of Server Actions is their deep integration with React Server Components (RSC). When you execute a Server Action, you can trigger a cache revalidation on the server using Next.js's revalidatePath or revalidateTag functions.
typescript // actions/post.ts 'use server'; import { revalidatePath } from 'next/cache'; import { db } from '@/lib/db';
export async function createComment(postId: string, content: string) {
await db.comment.create({ data: { postId, content } });
revalidatePath(/posts/${postId}); // Re-renders RSCs on the server!
}
When revalidatePath is called, Next.js does not trigger a full page reload. Instead, it re-renders the Server Components on the server, generates a fresh .rsc payload (containing the updated HTML structure), and streams it to the client. The client-side React runtime then reconciles this new data with the existing DOM tree, preserving client-side state (like input focus and scroll position).
This is a revolutionary pattern because it allows you to build highly dynamic, data-driven applications with zero client-side JavaScript for data fetching or cache management.
The Serial Execution Problem
However, this elegant model comes with a major catch: sequential execution.
If you trigger multiple Server Actions in a single event handler, React runs them in serial. This is designed to prevent race conditions during state revalidation, but it can severely degrade user experience if your actions involve slow network requests or database queries.
typescript // This runs sequentially, blocking the UI! async function handleUpload() { await uploadImage(image1); await uploadImage(image2); await uploadImage(image3); }
tRPC: Parallel Queries and Granular Caching
tRPC bypasses this limitation entirely. Because it uses TanStack Query under the hood, it fully supports parallel query execution, request batching, and highly granular client-side caching.
If you need to fetch data for five different dashboard widgets, tRPC can batch those requests into a single HTTP call or execute them in parallel, updating each widget's loading state independently. It also supports sophisticated optimistic updates out of the box, allowing you to update the UI instantly and roll back cleanly if the mutation fails.
The Next.js 15+ Mutation Landscape: Next.js Server Actions vs API Routes
Many developers struggle to understand when to use nextjs server actions vs api routes (Route Handlers) in modern Next.js applications.
+-----------------------------------------------------------------------------+ | ARCHITECTURAL DECISION FLOW | | | | Does this endpoint need to be accessed by external clients? | | (e.g., Mobile Apps, Public Webhooks, Third-Party Integrations) | | | | / \ | | / (Yes) \ (No) | | v v | | +------------------+ Is this a standard data | | | USE API ROUTES | mutation or form submit? | | | (Route Handlers) | | | +------------------+ / \ | | / (Yes) \ (No) | | v v | | +------------------+ +--------------+ | | USE SERVER | | USE TRPC / | | | ACTIONS | | API ROUTES | | +------------------+ +--------------+ +-----------------------------------------------------------------------------+
When to Use Server Actions
Server Actions are the ideal choice for mutations that are tightly coupled to the user interface. If you are building a form, a toggle button, a delete icon, or a simple search input, Server Actions eliminate the need to write boilerplate API endpoints.
- Forms and Buttons: Perfect for standard CRUD operations, settings pages, and interactive UI elements.
- Progressive Enhancement: Server Actions can run without client-side JavaScript. If a user is on a slow connection and the JS bundle has not fully hydrated, submitting a form using a Server Action will still work natively via standard HTML form submission.
- Cookie Management: You can read and write cookies directly inside a Server Action using
cookies().set(), making them excellent for authentication flows (login, logout, session refresh).
When to Use Route Handlers (API Routes)
Route Handlers are standard REST endpoints that live in your app/api directory. You should use them when your backend logic needs to exist independently of your React frontend.
- External Clients: If you have an iOS, Android, or desktop application that needs to communicate with your backend, you must use Route Handlers.
- File Uploads and Streaming: While Server Actions can handle small file uploads, large payloads or streaming data (like SSE or WebSockets) are much better suited for standard API routes.
- Webhooks: External services like Stripe, Clerk, or Twilio cannot trigger Server Actions. They require static, predictable API endpoints to send webhook payloads.
The 2026 Ecosystem: Top tRPC Alternatives and Server Action Libraries
To bridge the gap between the simplicity of Server Actions and the robust type safety of tRPC, the open-source community has created several powerful libraries. These are now considered the standard stack for React 19 development in 2026.
1. next-safe-action
next-safe-action is the most popular library for adding validation, type safety, and middleware to Next.js Server Actions. It effectively turns Server Actions into trpc alternatives that run natively within the Next.js runtime.
Here is how you define a validated, authenticated action using next-safe-action:
typescript // lib/safe-action.ts import { createSafeActionClient } from 'next-safe-action';
export const actionClient = createSafeActionClient();
// Create an authenticated client with middleware export const authedActionClient = actionClient.use(async ({ next }) => { const session = await getSession(); if (!session?.user) { throw new Error('Unauthorized'); } return next({ ctx: { userId: session.user.id } }); });
typescript // actions/post.ts 'use server'; import { authedActionClient } from '@/lib/safe-action'; import { z } from 'zod';
const createPostSchema = z.object({ title: z.string().min(3).max(100), content: z.string().min(10), });
export const createPost = authedActionClient .schema(createPostSchema) .action(async ({ parsedInput, ctx }) => { // parsedInput is fully typed: { title: string; content: string } // ctx.userId is safely passed from the middleware const post = await db.post.create({ data: { title: parsedInput.title, content: parsedInput.content, authorId: ctx.userId, }, }); return { post }; });
On the client, you can consume this action using a hook that provides loading, error, and success states:
typescript // components/CreatePost.tsx 'use client'; import { useAction } from 'next-safe-action/hooks'; import { createPost } from '@/actions/post';
export function CreatePostForm() { const { execute, result, status } = useAction(createPost);
return (
); }2. ZSA (Zod Server Actions)
ZSA is a formidable competitor to next-safe-action. It offers a highly declarative, procedure-based API that feels incredibly similar to tRPC, making it the perfect transition tool for teams moving away from tRPC.
One of ZSA's standout features is its first-class TanStack Query integration. This allows you to use Server Actions as queries, getting the best of both worlds: the simplicity of Server Actions and the powerful caching of React Query.
typescript // Using ZSA with TanStack Query on the client 'use client'; import { useServerActionQuery } from 'zsa-react'; import { getPostsAction } from '@/actions/post';
export function PostsList() { const { data, isPending } = useServerActionQuery(getPostsAction, { input: { page: 1 }, queryKey: ['posts'], });
if (isPending) return
Loading...
; return- {data?.posts.map(p =>
- {p.title} )}
3. Conform
While next-safe-action and ZSA handle the API layer, Conform focuses on the form validation state. It is designed specifically to work with Server Actions and progressive enhancement.
Unlike React Hook Form, which relies heavily on client-side state, Conform parses FormData on both the client and the server using your Zod schema. If validation fails on the server, Conform serializes the errors and sends them back to the client, allowing you to display field-level errors without shipping heavy client-side validation libraries to the browser.
Architectural Decision Matrix: When to Choose What in 2026
To help you choose the right architecture for your project, we have compiled a detailed feature comparison table reflecting the state of the ecosystem in 2026:
| Feature | Raw Server Actions | next-safe-action | ZSA (Zod Server Actions) | tRPC v11 | Standard REST (Route Handlers) |
|---|---|---|---|---|---|
| Input Validation | Manual | Built-in (Zod/Valibot) | Built-in (Zod) | Built-in (Zod/ArkType) | Manual |
| Output Validation | No | Yes | Yes | No | No |
| Middleware / Auth | Manual | Composable Pipelines | Reusable Procedures | Composable Middlewares | Manual / Global |
| Parallel Execution | No (Serial) | No (Serial) | Yes (via React Query) | Yes | Yes |
| Multi-Client Support | No | No | No | Yes (Native, Expo, etc.) | Yes |
| Progressive Enhancement | Yes | Yes | Yes | No | No |
| Client-Side Caching | No | No | Yes (via React Query) | Yes (via TanStack Query) | Yes (SWR / React Query) |
| Bundle Size Cost | Zero | Minimal | Minimal | Moderate | Moderate |
The Recommended 2026 Stack
For the vast majority of greenfield Next.js applications in 2026, we recommend the following unified stack:
- Form Handling: Conform (for progressive enhancement and nested form state).
- API & Mutations: next-safe-action or ZSA (for composable auth middleware and strict input validation).
- Data Fetching: React Server Components (fetching directly via async/await and ORMs like Prisma or Drizzle).
- Client-side State & Caching: SWR or TanStack Query (only when dynamic, client-side polling or infinite scrolling is required).
Key Takeaways / TL;DR
- Server Actions are compiled RPCs: They are not standard local functions; React compiles them into hashed HTTP POST endpoints automatically.
- tRPC is not dead, but its scope is narrower: It remains the gold standard for multi-client applications (web + mobile) and complex, non-React backend architectures.
- Raw Server Actions lack security and validation: You should never use raw Server Actions in production without a validation wrapper like
next-safe-actionorZSA. - The Serial Execution Bottleneck is real: Server Actions process sequentially by default. For highly parallel dashboard interfaces, tRPC or standard REST endpoints are more performant.
- Progressive Enhancement is a superpower: Server Actions combined with Conform allow your application's forms to function even before the client-side JavaScript has finished downloading.
Frequently Asked Questions
Is tRPC dead in 2026?
No, tRPC is not dead. While Server Actions have captured a massive share of the single-client Next.js ecosystem, tRPC remains the premier choice for applications that need to share type-safe APIs across multiple frontends (such as a Next.js web app and a React Native mobile app) or when working with standalone backends.
How do I handle Next.js server actions type safety without third-party libraries?
To achieve complete type safety without external libraries, you must manually parse and validate incoming data inside your Server Action using a schema validator like Zod. However, this requires significant boilerplate code for every endpoint. Using a library like next-safe-action or ZSA is highly recommended for production applications to automate this process.
Can I use Server Actions in a React Native (Expo) app?
No, you cannot directly import or call Server Actions inside a standalone React Native application. Server Actions are tightly bound to the bundler and deployment environment of your React web framework (like Next.js or Waku). For mobile applications, tRPC or a traditional REST/GraphQL API remains necessary.
What are the best tRPC alternatives for React 19?
The best alternatives to tRPC in React 19 are type-safe Server Action wrappers like next-safe-action and ZSA. If you are building a traditional REST API, ts-rest and oRPC are excellent alternatives that provide end-to-end type safety using OpenAPI contracts.
How do Next.js server actions vs API routes compare for security?
Both Server Actions and API Routes are public HTTP endpoints that can be targeted by malicious actors. However, because Server Actions look like standard local functions, developers occasionally forget to implement authentication and rate-limiting checks. From a security standpoint, you must treat every Server Action exactly like a public REST endpoint: validate inputs, verify user sessions, and apply rate limits.
Conclusion
The architectural battle of server actions vs trpc is not a question of which technology is objectively better, but rather where your application's boundaries lie.
If you are building a Next.js-centric web application where data mutations are closely tied to the user interface, React 19 Server Actions wrapped in a library like next-safe-action offer an unparalleled developer experience. They eliminate the friction of API routing, reduce your client-side bundle size, and allow you to leverage the full power of React Server Components.
However, if your roadmap includes a mobile application, external third-party integrations, or a distributed microservices architecture, tRPC remains a robust, battle-tested champion. It preserves the integrity of your API contracts across multiple repositories without locking you into a single framework's build system.
By understanding these tradeoffs, you can architect a highly performant, future-proof codebase that maximizes both developer productivity and end-user performance in 2026 and beyond.


