Server Actions ("use server"): Type-Safe Mutations Without API Endpoints0%
Form Handling with useActionState, useFormStatus & Zod Validation

Server Actions ("use server"): Type-Safe Mutations Without API Endpoints

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Server Actions ("use server"): Type-Safe Mutations Without API Endpoints

In traditional web development, submitting a form required creating an API endpoint (/api/feedback), setting up body parsers, managing HTTP methods, writing client-side fetch logic, and synchronizing state. Server Actions revolutionize data mutations by allowing client components and forms to invoke asynchronous server-side functions directly using the "use server" directive.


1. What are Server Actions?

A Server Action is an asynchronous function that executes exclusively on the server. They can be invoked:

  • Directly inside HTML <form action={myAction}> elements (works even if JavaScript is disabled!).
  • Programmatically from client components via event handlers or React hooks.
  • Provide end-to-end TypeScript type safety between the UI form and the database mutation.

2. Defining Server Actions in a Dedicated File

Placing server actions in a dedicated file marked with 'use server' allows them to be shared across Server and Client Components:

TypeScript
// app/actions/course-actions.ts
'use server';
 
import dbConnect from '@/lib/dbConnect';
import Course from '@/models/Course';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
 
export async function createCourseAction(formData: FormData) {
await dbConnect();
 
const title = formData.get('title') as string;
const price = Number(formData.get('price'));
const category = formData.get('category') as string;
 
// Validation
if (!title || title.length < 3) {
throw new Error('Course title must be at least 3 characters long');
}
 
// Database persistence
await Course.create({
title,
price,
category,
slug: title.toLowerCase().replace(/\s+/g, '-')
});
 
// Revalidate cache so the courses catalog immediately shows the new course!
revalidatePath('/courses');
 
// Redirect user to the courses list
redirect('/courses');
}

3. Consuming Server Actions in Components

TSX
// app/admin/courses/new/page.tsx
import { createCourseAction } from '@/app/actions/course-actions';
 
export default function NewCoursePage() {
return (
<div className="max-w-md mx-auto p-6 bg-white rounded-xl shadow-md">
<h2 className="text-xl font-bold mb-4">Create New Course</h2>
<form action={createCourseAction} className="space-y-4">
<div>
<label className="block text-sm font-medium">Course Title</label>
<input name="title" required className="w-full border p-2 rounded" />
</div>
<div>
<label className="block text-sm font-medium">Price (INR)</label>
<input name="price" type="number" required className="w-full border p-2 rounded" />
</div>
<button type="submit" className="w-full bg-blue-600 text-white p-2 rounded">
Publish Course
</button>
</form>
</div>
);
}

Interactive Quiz

Multiple Choice Questions

Question 1
What directive is required at the top of an action function or file to designate it as a Server Action?
Question 2
What is a key advantage of invoking Server Actions inside <form action={action}> compared to traditional onSubmit with fetch?
Question 3
What argument does a Server Action receive when invoked as the action attribute of an HTML <form>?
Question 4
Can a Server Action be called from an interactive Client Component with 'use client'?
Question 5
Why should you call revalidatePath('/courses') inside a Server Action that adds a new course?

Next Lesson

Form Handling with useActionState, useFormStatus & Zod Validation

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext