LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 3319 min read

Server Actions

Run server-side code directly from a form or button using the "use server" directive — no API endpoint required.

What Is a Server Action?

A Server Action is an async function marked with "use server" that always runs on the server, even when it's called from a Client Component in the browser. It gives you a way to mutate data — creating a record, updating a row — without hand-building a Route Handler and a fetch call to reach it.

Defining a Server Action

You can mark a whole file as server-only actions, or mark an individual function inline inside a Server Component.

// app/actions.ts
'use server';
export async function createPost(formData) {
const title = formData.get('title');
await db.post.create({ data: { title } });
revalidatePath('/blog');
}

Using It in a Form

Pass a Server Action directly to a form's action prop. Next.js handles the submission — including progressive enhancement, so the form still works even before client JavaScript finishes loading.

// app/blog/new/page.tsx — Server Component
import { createPost } from '../../actions';
export default function NewPostPage() {
return (
<form action={createPost}>
<input name="title" placeholder="Post title" />
<button type="submit">Create Post</button>
</form>
);
}
Progressive Enhancement

Because the form posts using standard HTML form semantics under the hood, it keeps working even if JavaScript hasn't loaded yet — a meaningful reliability win over a purely client-side fetch-based submit handler.

Calling a Server Action from an Event Handler

Server Actions also work from a Client Component's regular event handlers, not just a form's action prop — useful for a "like" button or any single-click mutation.

'use client';
import { likePost } from '../actions';
export default function LikeButton({ postId }) {
return (
<button onClick={() => likePost(postId)}>
👍 Like
</button>
);
}

How It Works Under the Hood

Next.js compiles a Server Action into a reference the client can safely call — under the hood, calling it triggers a POST request back to the server, where the actual function body runs. The client never sees your database queries or server-only logic; it only ever gets a callable reference.

Common Beginner Mistakes

Forgetting to revalidate after a mutation

Without revalidatePath or revalidateTag, the UI won't reflect the change until the cache naturally expires or the user hard-refreshes.

Treating a Server Action like a normal client-side function

Every call is a network round-trip to the server — don't call one in a tight loop or expect synchronous, instantaneous execution.

FAQs

No — they overlap for internal mutations, but Route Handlers are still needed for public APIs, webhooks, and custom response formats.

Yes — it can return a value the caller awaits, which is commonly combined with the useFormStatus and useFormState (useActionState) hooks for pending/error UI.

Summary

Server Actions let you write server-side mutations as plain async functions, callable directly from forms and event handlers. Next, you'll build a complete form with validation and pending states around this pattern.

Next Lesson →

Forms & Data Mutations