React Server Functions and Server Actions Explained

Server Functions let Client Components call async functions on the server. A Server Function passed to a form action is a Server Action.

7 min read

React Server Functions let Client Components call async functions that execute on the server. A Server Function becomes a Server Action when it is passed to a form action prop or called from inside an action, but not every Server Function is a Server Action. The feature is stable in React 19 and requires a framework that implements React Server Components.

The naming changed

Before September 2024, the React docs called every Server Function a Server Action. The current docs reserve Server Action for functions used as actions, which leaves Server Function as the general term.

Create and call a Server Function

A Server Function is created with the 'use server' directive. Mark a module to export Server Functions that client code can import directly.

App.jsxApp.jsx
'use server';
 
export async function createNote(title) {
  await db.notes.create(title);
}

Client code imports the function like any module, but the bundler replaces it with a server reference. Calling it performs a network request, so the call returns a Promise. The server reference carries only an identifier, never the function body, so the client cannot see or run the real implementation.

App.jsxApp.jsx
'use client';
 
import { createNote } from "./actions";
 
export default function NewNote() {
  return (
    <button onClick={() => createNote("Untitled")}>
      Create note
    </button>
  );
}

Clicking the button sends the title to the server and runs createNote there. The browser never receives the function body or the database module.

Server Functions as form actions

The most common use is a form action. Pass a Server Function to the action prop of a form, and React supplies the FormData as the first argument.

App.jsxApp.jsx
'use server';
 
export async function requestUsername(formData) {
  const username = formData.get("username");
  await db.usernames.request(username);
}

The function reads the username from the submitted FormData and persists it. Marking the whole module as server code is what lets the form import the function directly.

App.jsxApp.jsx
'use client';
 
import { requestUsername } from "./actions";
 
export default function UsernameForm() {
  return (
    <form action={requestUsername}>
      <input type="text" name="username" />
      <button type="submit">Request</button>
    </form>
  );
}

When the user submits, React sends the FormData to requestUsername and runs it on the server. The form can be submitted before the JavaScript bundle loads, because the action is progressively enhanced through the server. When the submission succeeds, React resets the uncontrolled input automatically, so the field clears without extra state.

Read results with useActionState

When the function must report success or failure, pair it with useActionState. The Hook returns the current state, a wrapped action, and a pending flag. It is a client Hook, so the form file keeps its 'use client' marker.

App.jsxApp.jsx
'use client';
 
import { useActionState } from "react";
import { requestUsername } from "./actions";
 
export default function UsernameForm() {
  const [state, formAction, isPending] = useActionState(requestUsername, null);
  return (
    <form action={formAction}>
      <input type="text" name="username" />
      <button type="submit" disabled={isPending}>
        {isPending ? "Requesting..." : "Request"}
      </button>
      <p>{state}</p>
    </form>
  );
}

The Server Function returns a value such as "successful" or "failed", and that value becomes the state the paragraph renders. The button disables while the request is pending.

useActionState also replays form submissions that happened before hydration, so early submissions are not lost. The wrapped action is what you pass to the form, while the raw Server Function stays available if you need to call it directly.

Call a Server Function outside a form

Outside a form, call the function inside a transition and await the result.

App.jsxApp.jsx
'use client';
 
import { useState, useTransition } from "react";
import { incrementLike } from "./actions";
 
export default function LikeButton() {
  const [likes, setLikes] = useState(0);
  const [isPending, startTransition] = useTransition();
  const onClick = () => {
    startTransition(async () => {
      setLikes(await incrementLike());
    });
  };
  return (
    <button onClick={onClick} disabled={isPending}>
      Like ({likes})
    </button>
  );
}

The transition keeps the existing UI responsive while the request runs. The returned count replaces the previous value once the server responds.

Outside a form there is no automatic FormData, so pass explicit arguments and await the result yourself. The pending flag disables the button to prevent duplicate clicks.

Security and limits

Every Server Function is a public endpoint from the client's point of view.

  • Validate every argument and authorize the signed-in user before mutating.
  • Use them for mutations, not data fetching, because frameworks process one at a time and do not cache results.
  • Keep secrets out of the return value, since it is serialized back to the client.

Treat a Server Function the way you would treat an API route: the request may be crafted, replayed, or sent by someone else entirely.

For the directive itself, see how the use server directive works. For the client boundary, see how the use client directive works. For the component model, start with React Server Components Explained.

Rune AI

Rune AI

Key Insights

  • Server Functions run async code on the server from client code.
  • A Server Action is a Server Function used as a form action.
  • Pass a Server Function to the form action prop for mutations.
  • useActionState exposes pending state and the last result.
  • Validate and authorize every call because arguments are untrusted.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between a Server Function and a Server Action?

A Server Action is a Server Function passed to a form action prop or called from inside an action. Before September 2024 the React docs called every Server Function a Server Action.

Can I use a Server Function to fetch data?

They are designed for mutations. Frameworks process one action at a time and do not cache the return value, so fetching belongs in a Server Component instead.

Conclusion

Server Functions let Client Components call async code on the server. They become Server Actions when wired to a form action, and they work with useActionState for pending state and progressive enhancement.