Creating Server Actions in Next.js
From the Next.js cheat sheet · Server Actions · verified Jul 2026
Creating Server Actions
typescript
// app/actions.ts - Separate file for actions
'use server'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { z } from 'zod'
// Simple server action
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
// Validate input
if (!title || !content) {
throw new Error('Title and content are required')
}
// Save to database
const post = await db.post.create({
data: { title, content }
})
// Revalidate cache
revalidatePath('/posts')
// Redirect
redirect(`/posts/${post.id}`)
}
// With validation using Zod
const CreatePostSchema = z.object({
title: z.string().min(1).max(100),
content: z.string().min(10),
published: z.boolean().default(false),
})
export async function createPostValidated(formData: FormData) {
const validatedFields = CreatePostSchema.safeParse({
title: formData.get('title'),
content: formData.get('content'),
published: formData.get('published') === 'true',
})
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
}
}
const post = await db.post.create({
data: validatedFields.data
})
revalidatePath('/posts')
redirect(`/posts/${post.id}`)
}
// Inline server action in Server Component
async function ServerComponent() {
async function deletePost(id: string) {
'use server'
await db.post.delete({ where: { id } })
revalidatePath('/posts')
}
return <form action={deletePost}>...</form>
}💡 Functions that run on server, called from client
⚡ Replace API routes for mutations
📌 Use "use server" directive
🔥 Automatically handle form submissions