[ReactJS]

3 Oct 2025

-

4 min read time

The ultimate guide to React Server Actions

Discover how React Server Actions are revolutionizing data mutations in Next.js by enabling secure, server-run async functions without extra API routes. Learn to extend them with custom hooks, error handling, optimistic updates, and third-party integrations for seamless, robust workflows.

Kalle Bertell

By Kalle Bertell

The ultimate guide to React Server Actions

Mastering React Server Actions: The Future of Data Mutations

By the end of this article, you’ll understand how React Server Actions work, why they’re rewriting the rules for data mutations, and how to extend them with custom hooks, error handling patterns, and third-party integrations.

What Are React Server Actions?

React Server Actions are asynchronous functions that live and run on the server. You define them by placing "use server" at the top of your function file, then call them directly from Server or Client Components without writing separate API routes. For full details, see the Next.js Data and Mutations documentation.

Key benefits:

  • Security: sensitive operations stay on the server, but the action is still callable by direct POST requests; check authentication and authorization inside it

  • Reduced boilerplate: no need for `/api/*` endpoints

  • Progressive form enhancement: forms keep working even if JavaScript fails

Image

Getting Started with Server Actions

  1. In a Next.js component file, create your action. This sketch assumes an application-specific server-side getCurrentUser() function and a configured db client:

      "use server";
    
    export async function addPost(data) {
      const user = await getCurrentUser();
      if (!user || !user.canCreatePost) throw new Error("Forbidden");
    
      const title = data.get("title");
      if (typeof title !== "string" || !title.trim()) {
        throw new Error("Invalid title");
      }
    
      await db.post.create({ data: { title: title.trim() } });
    }
    
  2. Import and pass it into a Client Component:

      <NewPostForm action={addPost} />
    
  3. To manage action state in a Client Component, use `useActionState()` from `react`; its third returned value, `isPending`, indicates whether the action is running. See the React useActionState documentation.

Step

Description

Create Server Action

Define an async function with "use server"

Pass to Client Component

Import and use action prop in component

Manage Form State

Use useActionState() to read action state and isPending

Optimistic Updates & Revalidation

  • Optimistic UI: immediately show a new post in the list while the server call runs

  • Revalidation: after mutation, re-fetch or revalidate data with the built-in Next.js caching tools

Feature

Purpose

Implementation

Optimistic UI

Show immediate updates

Update UI before server response

Revalidation

Fetch fresh data

Use Next.js caching/revalidation APIs

Advanced Workflows and Form Handling

Server Actions also need authorization and error handling for destructive operations. In this sketch, getCurrentUser() represents your application's server-side session lookup. Return an error if deletion fails, and call redirect() only after the try/catch so the redirect itself is not caught:

  "use server";

import { redirect } from "next/navigation";

export async function deleteAccount(id) {
  const user = await getCurrentUser();
  if (!user || user.id !== id) throw new Error("Forbidden");

  try {
    await db.user.delete({ where: { id: user.id } });
  } catch (error) {
    return { error: "Could not delete account" };
  }

  redirect("/goodbye");
}

In a Server Action, redirect() navigates on the client when JavaScript is available; a form submission without JavaScript uses HTTP 303. See the Next.js redirect documentation for the behavior in other contexts.

Extending Server Actions: Custom Hooks & Context

While Next.js provides the basics, you can layer extra ergonomics:

  • useServerAction: a hook that wraps your action with built-in error boundaries and loading states

  • useOptimisticServerAction: automates optimistic updates (rollback on failure)

  • Interceptors & runtime context: inject analytics, logging, or database clients into every call

Hook/Pattern

Functionality

useServerAction

Error boundaries and loading states

useOptimisticServerAction

Automates optimistic updates with rollback

Interceptors & runtime context

Injects analytics, logging, or clients into actions

Integrating with Third-Party Libraries

You’re not limited to Next.js alone. Here’s how Server Actions can play with other tools:

  • Authentication (Clerk)

      "use server";
    
    import { auth } from "@clerk/nextjs/server";
    
    export async function secureAction() {
      const { userId } = await auth();
      if (!userId) throw new Error("Not signed in");
    
      // Check this user's permission for the specific mutation here.
    }
    

    Clerk's server-side `auth()` helper is asynchronous; authentication should be followed by permission checks for the specific operation. See Clerk's Server Actions documentation.

  • Type-Safe RPC (oRPC)

    Define schemas for your Server Actions to ensure request and response shapes match perfectly. Learn more in the oRPC overview guide.

A New Era of Mutation

You’ve seen how React Server Actions simplify data handling, combine with third-party services, and let you build rich forms and workflows without extra API layers. By adopting custom hooks, structured error objects, and runtime interceptors, you can tailor them to any architecture.

Happy coding!

Kalle Bertell

By Kalle Bertell

More from our Blog

Keep reading