Next.js + Server Actions + Shadcn UI
Forms with Server Actions, Zod validation, and Shadcn UI primitives.
# CLAUDE.md — Next.js + Server Actions + Shadcn UI
## Forms & mutations
- Use Server Actions for every form. The client form component imports the action and passes it to `<form action={...}>`.
- Validate input inside the action with Zod. Reject invalid input before touching the database.
- Return a discriminated `{ ok: true, data } | { ok: false, error }` from every action. The client renders state from this — never throws.
- Use the `useActionState` (or `useFormState`) hook to keep server-returned errors next to the form fields.
- For optimistic UI, use `useOptimistic` — don't manually duplicate state.
## Shadcn UI
- Components live in `components/ui/`. Generated with `npx shadcn add <component>` — keep them under your control.
- Compose from primitives: never reach for a "kitchen sink" library on top of Shadcn.
- For variants, extend the existing `cva` class string — don't fork the file.
- Re-export Shadcn primitives from a single barrel only if you also wrap them. Otherwise import directly from `components/ui/<file>`.
- Shadcn components are client components by default. If a primitive is purely presentational, copy it into a server component file and drop the `'use client'` directive.
## Validation
- One Zod schema per form, exported from `lib/validators/<feature>.ts`.
- Infer types: `type FormInput = z.infer<typeof formSchema>`. Never declare the type by hand.
- Reuse the schema on the client (resolver for `react-hook-form`) and the server (action input check). Don't duplicate.
## Patterns
- Loading states: use the `pending` flag from `useActionState` — don't track it with `useState`.
- After a successful mutation, call `revalidatePath` or `revalidateTag` from the action — not `router.refresh()` from the client.
- Handle redirects with `redirect()` *inside* the action. The client never decides where to go after a mutation.
## Don't
- Don't wrap a Server Action in a fetch from a client. Pass it to `<form action>` or call it directly via `useTransition`.
- Don't return raw `Error` objects — they don't serialize. Return shape-checked plain objects.
- Don't put business logic in form components. Keep the form thin; logic lives in the action.
- Don't mix Shadcn with another UI kit. Pick one design system and commit.
Other Next.js templates
Next.js App Router + TypeScript Rules
Server Components, Server Actions, and TypeScript discipline for the Next.js App Router.
Next.js + Supabase Auth
Auth flows with Supabase SSR, cookies, and Row Level Security policies.
Next.js + Tailwind + Prisma Stack
Full-stack Next.js with Prisma ORM, Tailwind CSS, and Postgres.
Next.js SEO + Metadata Rules
Metadata API, sitemap, robots, OG images, and structured data done right.