Skip to content
Daily Dev Tip

This tip lives in your new tab — for free.

Install for Chrome →
NEXT

Use Server Actions for internal mutations instead of hand-rolled API routes

app/actions/posts.ts
typescript
'use server'
import { z } from 'zod'
import { revalidatePath } from 'next/cache'

const schema = z.object({ title: z.string().min(1) })

export async function createPost(formData: FormData) {
  const { title } = schema.parse({ title: formData.get('title') })
  await db.post.create({ data: { title } })
  revalidatePath('/blog')
}

Server Actions run mutation logic on the server and can be called directly from a `<form action>` or a client handler — no `/api` endpoint to define, wire up, and fetch for internal writes. Validate the payload server-side (Zod here) since anything reaching an action is untrusted input. Reserve dedicated Route Handlers for public APIs consumed by external clients; for your own create/update/delete flows, actions colocate the logic with its trigger.

nextjs15server-actionsmutationsvalidation