Next.js Form Handling in 2026: Server Actions, React Hook Form, and Conform Compared

#next.js form handling
Sandor Farkas - Founder & Lead Developer at Wolf-Tech

Sandor Farkas

Founder & Lead Developer

Expert in software development and legacy code optimization

Next.js form handling in 2026 has three viable paths, and picking the wrong one costs a team weeks of rework once a form grows past a single text field. Server Actions have matured since their early days, React Hook Form remains the default for anything with real client validation, and Conform has quietly become the library that bridges the two. For a B2B SaaS team building forms with conditional fields, file uploads, and dynamic arrays, the choice is not cosmetic. It determines how much JavaScript ships to the browser, how validation errors reach the user, and how much code has to be rewritten when a designer asks for optimistic UI six months from now.

This post compares the three approaches using the same form: a project creation form with required fields, a conditional field that appears based on project type, and a file upload. The goal is not to crown one winner but to show where each one earns its keep.

Pure Server Actions

A Server Action is a function marked with 'use server' that runs on the server and can be called directly from a form's action prop. For a form with two or three fields and no client-side interactivity, this is the least code you can write.

async function createProject(formData: FormData) {
  'use server';
  const name = formData.get('name');
  const type = formData.get('type');
  // validate, then insert into the database
}

export default function NewProjectForm() {
  return (
    <form action={createProject}>
      <input name="name" required />
      <select name="type">
        <option value="internal">Internal</option>
        <option value="client">Client</option>
      </select>
      <button type="submit">Create</button>
    </form>
  );
}

No client bundle, no state management, and the form still works with JavaScript disabled. The catch shows up the moment the form needs a conditional field. Showing a "client name" field only when type is "client" requires client-side state to track the selected value, which means the form is no longer a pure server component. Error display has the same problem: without useFormState (now useActionState) wired up, a failed validation just reloads the page with no indication of what went wrong. Server Actions work well for simple, mostly-static forms. Once a form needs to react to its own input in real time, plain Server Actions start fighting the framework instead of using it.

React Hook Form with API routes

React Hook Form has been the standard for complex forms in React for years, and that has not changed. It manages field state, validation, and re-renders on the client, then submits to an API route handler.

const { register, handleSubmit, watch } = useForm();
const projectType = watch('type');

async function onSubmit(data: FormValues) {
  const res = await fetch('/api/projects', {
    method: 'POST',
    body: JSON.stringify(data),
  });
  if (!res.ok) {
    // set field errors from the response
  }
}

This is the right tool for the project creation form once conditional fields, field arrays, or async validation (checking if a project name is already taken, for example) enter the picture. watch makes the conditional client field trivial. Field arrays for something like "add another team member" are a first-class feature. The tradeoff is that every field, error message, and loading state has to be wired by hand, and the form ships its own client bundle regardless of how simple the fields end up being.

Conform

Conform sits between the two. It is built to work with Server Actions and progressive enhancement, but it gives back the validation ergonomics that plain Server Actions lack, including full Zod schema support and structured error objects.

const schema = z.object({
  name: z.string().min(1),
  type: z.enum(['internal', 'client']),
  clientName: z.string().optional(),
});

export default function NewProjectForm() {
  const [form, fields] = useForm({
    onValidate({ formData }) {
      return parseWithZod(formData, { schema });
    },
  });

  return (
    <form {...getFormProps(form)} action={createProject}>
      <input {...getInputProps(fields.name, { type: 'text' })} />
      <div>{fields.name.errors}</div>
      <button type="submit">Create</button>
    </form>
  );
}

The form still submits through a Server Action, so it degrades gracefully without JavaScript, but Conform layers in the same schema validation on both client and server, conditional field rendering driven by form state, and typed error objects per field. For the project creation form, this means the same Zod schema validates the client-name-when-type-is-client rule and the file upload constraint, with no duplicated logic between client and server. The cost is a steeper learning curve than React Hook Form and a smaller ecosystem of examples to draw from, since Conform is newer and less widely adopted.

The comparison in practice

Running the same project creation form through all three approaches produces a clear pattern. Code volume is lowest for pure Server Actions and highest for React Hook Form once error handling and conditional logic are included, with Conform landing in between. Validation behavior differs more than code volume does: Server Actions validate only after submission unless extra plumbing is added, React Hook Form validates continuously on the client with a manual sync back to server-side checks, and Conform validates on both sides from a single schema. Error display is the weakest point for plain Server Actions, competent for React Hook Form, and the strongest of the three for Conform because errors are typed per field automatically.

For a form with one or two fields and no interactivity, pure Server Actions is still the right default. It ships the least code and needs no dependency beyond Next.js itself. For a form with genuinely complex client-only interaction, drag-and-drop reordering of field arrays or heavy optimistic UI, React Hook Form remains the more flexible choice, especially for teams already comfortable with it. For everything in between, which in our experience covers most B2B SaaS forms, Conform is worth the ramp-up time. Getting Server Action semantics with proper validation and progressive enhancement in one library removes a category of bugs that shows up later: the client validation and server validation quietly drifting out of sync.

Testing and migrating between approaches

Testing effort also differs across the three patterns, and it is worth planning for before a team commits. Server Actions can be tested as plain async functions, calling them directly with a mock FormData object, which keeps unit tests simple. React Hook Form components need a rendering library like Testing Library and some setup to fill fields and trigger validation, since the state lives inside the hook. Conform forms fall closer to React Hook Form in testing effort, because the schema can be tested independently of the component with plain Zod assertions, but the rendered form still needs the same Testing Library setup for interaction tests.

Migrating an existing form between these patterns is rarely a full rewrite. A form built with plain Server Actions that has outgrown them usually only needs the validation schema extracted and Conform's useForm and getFormProps wrapped around the existing markup, since the Server Action itself can stay mostly unchanged. Moving a React Hook Form implementation to Conform is more work, since the field registration API is different enough that most of the JSX needs to be touched, but the Zod schema, if one already exists, transfers directly. Teams considering the move should budget for the schema work being reusable and the component work not being reusable.

What this means for your team

Teams building custom software often default to whichever pattern the first engineer on the project happened to know, and that choice tends to stick for the life of the codebase. If your Next.js application has a mix of simple and complex forms scattered across three different patterns, that inconsistency is a sign the original decision was never revisited. A short architecture review can settle which pattern fits which class of form and save a rewrite later.

If your team is choosing a form strategy for a new web application or auditing an existing one that has grown inconsistent, we help SaaS teams make this call as part of broader custom software development work. Reach out at hello@wolf-tech.io or visit wolf-tech.io to talk through your specific forms and constraints.