web

Next.js 14 Server Actions: Complete Guide

MC
Michael Chen
Full Stack Developer
📅 Dec 3, 2024⏱️ 10 min read
#Next.js#React#Server Actions

Next.js 14 Server Actions: Complete Guide

Server Actions in Next.js 14 represent a paradigm shift in how we build full-stack React applications. They eliminate the need for separate API routes and provide a seamless way to execute server-side code directly from your components.

What Are Server Actions?

Server Actions are asynchronous functions that run on the server and can be called directly from Client Components. They're built on top of React Server Components and provide:

  • Type Safety: End-to-end TypeScript support
  • Progressive Enhancement: Work without JavaScript
  • Optimistic Updates: Instant UI feedback
  • Automatic Revalidation: Smart cache updates

Basic Server Action

Let's start with a simple example:

'use server' import { revalidatePath } from 'next/cache' import { db } from '@/lib/db' export async function createPost(formData: FormData) { const title = formData.get('title') as string const content = formData.get('content') as string await db.post.create({ data: { title, content } }) revalidatePath('/posts') }

Using Server Actions in Forms

Server Actions work beautifully with HTML forms:

'use client' import { createPost } from './actions' export function CreatePostForm() { return ( <form action={createPost}> <input name="title" required /> <textarea name="content" required /> <button type="submit">Create Post</button> </form> ) }

Advanced Patterns

With useFormStatus

Show loading states during submission:

'use client' import { useFormStatus } from 'react-dom' function SubmitButton() { const { pending } = useFormStatus() return ( <button type="submit" disabled={pending}> {pending ? 'Creating...' : 'Create Post'} </button> ) }

Optimistic Updates

Provide instant feedback:

'use client' import { useOptimistic } from 'react' import { addTodo } from './actions' export function TodoList({ todos }) { const [optimisticTodos, addOptimisticTodo] = useOptimistic( todos, (state, newTodo) => [...state, newTodo] ) async function formAction(formData) { const todo = { id: Date.now(), text: formData.get('text') } addOptimisticTodo(todo) await addTodo(formData) } return ( <form action={formAction}> {optimisticTodos.map(todo => ( <div key={todo.id}>{todo.text}</div> ))} <input name="text" /> <button type="submit">Add</button> </form> ) }

Error Handling

Proper error handling with try-catch:

'use server' import { z } from 'zod' const schema = z.object({ email: z.string().email(), password: z.string().min(8) }) export async function createUser(formData: FormData) { try { const data = schema.parse({ email: formData.get('email'), password: formData.get('password') }) await db.user.create({ data }) return { success: true } } catch (error) { return { error: 'Invalid input' } } }

Database Operations

Server Actions are perfect for database mutations:

'use server' import { prisma } from '@/lib/prisma' import { revalidateTag } from 'next/cache' export async function updateUser(userId: string, data: UserData) { await prisma.user.update({ where: { id: userId }, data }) revalidateTag(`user-${userId}`) }

Authentication

Secure your actions with authentication:

'use server' import { auth } from '@/lib/auth' import { redirect } from 'next/navigation' export async function deletePost(postId: string) { const session = await auth() if (!session) { redirect('/login') } await db.post.delete({ where: { id: postId } }) }

Best Practices

  1. Always validate input: Use Zod or similar libraries
  2. Revalidate strategically: Only revalidate what changed
  3. Handle errors gracefully: Return error states, don't throw
  4. Keep actions focused: One action, one responsibility
  5. Use TypeScript: Full type safety end-to-end

Performance Considerations

  • Actions are automatically code-split
  • Only action code ships to the client
  • Parallel actions are automatically optimized
  • Built-in request deduplication

Conclusion

Server Actions are a game-changer for Next.js development. They simplify full-stack development, improve type safety, and provide excellent user experience with progressive enhancement.

Start using Server Actions today and experience the future of React development!

MC
About the Author

Michael Chen

Full Stack Developer

Michael is a Full Stack Developer specializing in Next.js and React. He has contributed to several open-source projects and loves sharing his knowledge through technical writing.

Want to Learn More?

Explore our other articles or get in touch with our team for custom solutions.