Server Action with Zod Validation

6 min read

Creating a user-friendly and secure registration form is essential for any application that manages user data. In this tutorial, we'll build a registration form in Next.js, leveraging the power of Zod for schema validation to ensure our data is valid.

Step 1: Create Form Schema with Zod

We start by defining our form schema using Zod, a schema declaration and validation library. It allows us to create a schema for our form data and provides useful error messages.

import * as z from 'zod';

export const registerFormSchema = z.object({
  email: z.string().email('This is not a valid email.'),
  password: z.string().min(6, 'Password must be at least 6 characters long'),
  passwordConfirm: z.string(),
}).refine(data => data.password === data.passwordConfirm, {
  message: "Passwords don't match",
  path: ['passwordConfirm'],

export type RegisterInputs = z.infer<typeof registerFormSchema>;

This schema ensures that the email is valid, the password has a minimum length, and both passwords match.

Step 2: Prepare Form Inputs Array

Next, we prepare our form inputs as an array, which allows us to dynamically generate our form fields.

export const registerFormItems: { key: 'email' | 'password' | 'passwordConfirm', type: string, label: string, placeholder: string }[] = [
    key: 'email',
    type: 'email',
    label: 'Email',
    placeholder: '',
    key: 'password',
    type: 'password',
    label: 'Password',
    placeholder: '********',
    key: 'passwordConfirm',
    type: 'password',
    label: 'Confirm Password',
    placeholder: '********',

Step 3: Implement Form Using NextUI

We use NextUI for a sleek and modern UI. The form is straightforward, with input fields generated based on our array.

// Inside your React component
return (
  <form onSubmit={handleSubmit(processForm)}>
    <div className="space-y-3">{renderItems}</div>
    <SubmitButton label="Create Account" />

Each input field is validated on-the-fly using our Zod schema.

Step 4: Implement Server Action with Zod Validation

We define a server-side action that validates the incoming form data using our Zod schema.

export const registerAction = async (formData: RegisterInputs) => {
  // Validate payload with Zod
  const result = registerFormSchema.safeParse(formData);
  if (result.error) {
    // handle validation errors
  // If valid, continue with registration logic...

This action ensures the data is correct before proceeding with further server-side logic, like storing the data in a database.

Step 5: Call Server Action on Submit

Finally, we handle the form submission on the client side by calling our server action. We pass the form data to our server action and handle the response accordingly.

const processForm: SubmitHandler<RegisterInputs> = async (data) => {
  const res = await registerAction(data);
  // Handle the response, updating UI with success or error messages

By calling the server action upon form submission, we leverage Next.js's server-side capabilities to validate and process our form.


In this guide, we've created a robust registration form using Next.js and Zod. This approach ensures that the client-side experience is smooth and that the server-side handling is secure and efficient.

Remember to test your form thoroughly to make sure all validations are working as expected and that the user experience is seamless.

Happy coding!