Form Validation in Next.js Using Yup

May 20, 2025

Tomek

Building forms is a common task in web development, but making sure users fill them out correctly can be tricky. If you’ve ever had a form submit with a missing email or a password that’s too short, you know how important good validation is. In the Next.js world, Yup is a favorite tool for this job because it’s flexible, readable, and integrates well with popular form libraries.

Let’s walk through how you can use Yup for form validation in a Next.js app, with clear examples and tips to make your forms robust and user-friendly.

What Is Yup?

Yup is a JavaScript library for schema-based validation. You describe the shape and rules for your data in a schema, and Yup checks if the data matches. If something’s off—like a missing field or an invalid email—Yup lets you know exactly what went wrong.

Setting Up Yup in Your Next.js Project

First, you’ll want to add Yup to your project. Open your terminal and run:

npm install yup

Or, if you’re using Yarn:

yarn add yup

Creating a Validation Schema

Suppose you’re building a sign-up form. You want to make sure the user enters a name, a valid email, and a password that’s at least 8 characters long. Here’s how you’d set up a Yup schema for that:

import * as yup from 'yup';

const schema = yup.object().shape({
  name: yup.string().required('Name is required'),
  email: yup.string().email('Please enter a valid email').required('Email is required'),
  password: yup.string().min(8, 'Password must be at least 8 characters').required('Password is required'),
});

This schema acts like a checklist for your form. If any rule isn’t met, Yup will return a clear error message.

Integrating Yup with a Next.js Form

You can use Yup on its own, but it really shines when paired with a form library. Let’s see how it works with Formik, a popular choice for managing form state in React and Next.js.

Here’s a simple registration form:

import React from 'react';
import { useFormik } from 'formik';
import * as yup from 'yup';

const validationSchema = yup.object({
  name: yup.string().required('Name is required'),
  email: yup.string().email('Please enter a valid email').required('Email is required'),
  password: yup.string().min(8, 'Password must be at least 8 characters').required('Password is required'),
});

export default function RegisterForm() {
  const formik = useFormik({
    initialValues: { name: '', email: '', password: '' },
    validationSchema,
    onSubmit: (values) => {
      alert(JSON.stringify(values, null, 2));
    },
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <label>
        Name:
        <input
          name="name"
          value={formik.values.name}
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
        />
      </label>
      {formik.touched.name && formik.errors.name && <div>{formik.errors.name}</div>}

      <label>
        Email:
        <input
          name="email"
          type="email"
          value={formik.values.email}
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
        />
      </label>
      {formik.touched.email && formik.errors.email && <div>{formik.errors.email}</div>}

      <label>
        Password:
        <input
          name="password"
          type="password"
          value={formik.values.password}
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
        />
      </label>
      {formik.touched.password && formik.errors.password && <div>{formik.errors.password}</div>}

      <button type="submit">Register</button>
    </form>
  );
}

As the user fills out the form, Yup checks each field. If something’s wrong, the error message appears right below the field.

Validating on the Server

Client-side validation is great for user experience, but it’s not enough on its own. Users can bypass it, so you should always validate again on the server. With Next.js API routes, you can use the same Yup schema to check incoming data:

import * as yup from 'yup';

const schema = yup.object({
  name: yup.string().required(),
  email: yup.string().email().required(),
  password: yup.string().min(8).required(),
});

export default async function handler(req, res) {
  try {
    await schema.validate(req.body, { abortEarly: false });
    // Proceed with processing
    res.status(200).json({ message: 'Success!' });
  } catch (err) {
    res.status(400).json({ errors: err.errors });
  }
}

Wrapping Up

Yup makes form validation in Next.js straightforward and reliable. By describing your rules in a schema, you can keep your code clean and your forms robust. Whether you’re working with Formik, React Hook Form, or just plain React state, Yup helps you deliver a better experience for your users - and fewer headaches for yourself.

If you’re building forms in Next.js, give Yup a try and reduce bugs, and make your forms much easier to maintain. If you want to save some more time make sure to check mailik.dev, easy way to manage your form without a need to setup any form backend.

Try Mailik

Set up your first project in a few minutes and gather form responses from your websites in one place