back
typescript·next.js

Next.js Server Action with Zod Validation

A complete server action pattern: Zod validation, error handling, and revalidation.

#next.js#typescript#zod#forms

typescript
'use server';

import { z } from 'zod';
import { revalidatePath } from 'next/cache';
import { db } from '@/app/db/drizzle';
import { projects } from '@/app/db/schema';

const CreateProjectSchema = z.object({
  title: z.string().min(3).max(255),
  description: z.string().min(10),
  technologies: z.array(z.string()).min(1),
});

type FormState = {
  success: boolean;
  errors?: Record<string, string[]>;
  message?: string;
};

export async function createProject(
  prevState: FormState,
  formData: FormData
): Promise<FormState> {
  const raw = {
    title: formData.get('title'),
    description: formData.get('description'),
    technologies: formData.getAll('technologies'),
  };

  const parsed = CreateProjectSchema.safeParse(raw);

  if (!parsed.success) {
    return {
      success: false,
      errors: parsed.error.flatten().fieldErrors,
    };
  }

  await db.insert(projects).values({
    ...parsed.data,
    slug: parsed.data.title.toLowerCase().replace(/s+/g, '-'),
  });

  revalidatePath('/projects');
  return { success: true, message: 'Project created!' };
}

more snippets