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

More Next.js tasks

Back to the full Next.js cheat sheet