Next Server Actions Zod Validation

Validate Next.js server action input with Zod before any mutation, returning typed field errors for progressive enhancement without JS.

TypescriptNextForm Validation

Code

snippet
import { z } from 'zod';
import { revalidatePath } from 'next/cache';

const FeedbackSchema = z.object({
  email: z.string().email(),
  rating: z.coerce.number().int().min(1).max(5),
  message: z.string().min(10).max(1000),
});

export type FeedbackState =
  | { status: 'idle' }
  | { status: 'error'; fields: Record<string, string> }
  | { status: 'success'; ticket: string };

export async function submitFeedback(
  _prev: FeedbackState,
  formData: FormData,
): Promise<FeedbackState> {
  const parsed = FeedbackSchema.safeParse({
    email: formData.get('email'),
    rating: formData.get('rating'),
    message: formData.get('message'),
  });

  if (!parsed.success) {
    const fields: Record<string, string> = {};
    for (const issue of parsed.error.issues) {
      fields[issue.path.join('.')] ??= issue.message;
    }
    return { status: 'error', fields };
  }

  const ticket = 'FB-' + Date.now().toString(36);
  revalidatePath('/feedback');
  return { status: 'success', ticket };
}