Joi: Declarative Schemas for Data Validation
Joi lets you describe your data's shape with a readable schema instead of writing manual validation logic. It's used to validate API request bodies or config files.
WHY IT EXISTS: Manual data validation is error-prone, repetitive, and hard to read. Checking if a field exists, is the right type, has a certain length, and relates to other fields creates nested if statements that are difficult to maintain. Joi was created to replace this imperative code with a single, declarative schema object that serves as the source of truth for your data's shape.
THE MENTAL MODEL: Think of a Joi schema as a contract or a blueprint for your data. You don't write the steps to check the data; you describe what the final, valid data must look like. Joi is the inspector that takes your blueprint and checks if the data conforms to it, providing a detailed report of any violations. It separates the "what" (the schema) from the "how" (the validation engine).
HOW IT WORKS: You import Joi and create a schema using Joi.object(). Inside, you define keys and chain validation rules to them, like Joi.string().email().required(). To validate data, you call schema.validate(yourDataObject). This returns an object containing error and value. If error is null, validation passed. If not, the error object contains a rich, detailed list of every validation failure, including the field path, message, and type of error. You can also define complex relationships, like requiring one field if another is present (.with()) or making fields mutually exclusive (.xor()).
WHEN TO USE IT: Use Joi for validating any data where the structure is known but the content is untrusted. Its primary use case is in API backends (like Express or Hapi) to validate incoming request bodies, query parameters, and headers. It's also excellent for validating application configuration files or environment variables at startup to fail fast with clear errors.
WHEN NOT TO USE IT: Joi is for validation, not sanitization. While it can coerce types (e.g., convert a string "123" to the number 123), it's not a tool for removing malicious input like XSS attacks. For that, you need a dedicated sanitization library. For very simple, one-off checks, a quick typeof check might be sufficient, though a schema is often more robust long-term.
ONE CANONICAL EXAMPLE: A common use case is validating a user registration form where a password and confirmation must match. The schema can use Joi.ref() to create this dependency without any custom logic. const schema = Joi.object({ password: Joi.string().min(8).required(), confirmPassword: Joi.any().valid(Joi.ref('password')).required() }); This declaratively states that confirmPassword must be identical to the value of password.
Read the original → joi.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.