Data Validation in JavaScript (Node.js): Joi, Yup, Zod

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Data Validation in Node.js: Joi, Yup and Zod — Choosing the Right Tool



In modern web development with Node.js, data validation is not just a good practice, but a necessity. Without it, your server risks receiving incorrect, malicious, or simply unexpected data from the client. This can lead to errors in application logic, vulnerabilities (SQL injection, XSS), and unstable operation. In this article, we will cover the three most popular libraries for data validation in the Node.js environment: Joi, Yup, and Zod. You will learn their features, advantages, and how to apply them in practice.



Why is server-side validation necessary?



Many developers rely only on frontend validation (e.g., using HTML5 attributes). This is a mistake. Client-side validation is easy to bypass (by disabling JavaScript or sending a request via Postman/curl). Server-side validation is the last line of defense. It ensures that only data meeting strict requirements enters your business logic and database: correct type, length, format (email, URL), field requiredness, etc.



1. Joi — The Proven Veteran



Joi (often used with the Hapi.js framework, but works great with Express/Koa as well) is one of the most powerful and flexible libraries. It provides a rich API for describing schemas and error messages.



Installation:

npm install joi


Example of using Joi for user registration validation:

const Joi = require('joi');

const schema = Joi.object({ username: Joi.string() .alphanum() .min(3) .max(30) .required() .messages({ 'string.min': 'Username must be at least {#limit} characters', 'string.max': 'Username must be at most {#limit} characters' }), password: Joi.string() .pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')) .required(), email: Joi.string() .email({ minDomainSegments: 2, tlds: { allow: ['com', 'net', 'ru'] } }) .required(), birth_year: Joi.number() .integer() .min(1900) .max(2023)});

const validateUser = (data) => { const { error, value } = schema.validate(data, { abortEarly: false }); if (error) { // Return all errors return { valid: false, errors: error.details.map(d => d.message) }; } return { valid: true, data: value };};

// Example callconst result = validateUser({ username: 'jo', password: '123', email: 'test@test', birth_year: 1800});console.log(result.errors);// Output: ['Username must be at least 3 characters', '"password" length must be at least 3 characters long', '"email" must be a valid email', '"birth_year" must be less than or equal to 2023']


Pros of Joi:

  • Huge number of built-in validators (email, URL, UUID, credit card, phone, etc.).
  • Support for conditional validation (when, switch).
  • Excellent error messages with translation and customization capabilities.
  • Detailed documentation.

Cons:

  • Library size (about 60 KB minified).
  • API can feel cumbersome for simple schemas.
  • Complex integration with TypeScript (requires additional types).


2. Yup — Simplicity and Composition



Yup was originally created for form validation in React (in conjunction with Formik), but it works great on the server as well. Its main advantage is a concise and readable syntax, reminiscent of mongoose schemas.



Installation:

npm install yup


Example of validating an array of objects using Yup:

const yup = require('yup');

cons

Recommendations