Expressive
Over 150 built-in validators across strings, numbers, dates, arrays, objects, binaries, and more — with chainable rules that read like English.
The most powerful schema description language and data validator for JavaScript

npm install joiyarn add joipnpm add joiimport Joi from 'joi';
const schema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required(),
email: Joi.string().email().required(),
age: Joi.number().integer().min(18),
});
const { error, value } = schema.validate({
username: 'danilo',
email: 'danilo@example.com',
age: 28,
});.alter() + .tailor() Define one schema. Produce specialized versions for different contexts — like separate validation for GET vs POST — without duplicating anything.
const schema = Joi.object({
id: Joi.number().alter({
create: (s) => s.forbidden(),
update: (s) => s.required(),
}),
name: Joi.string().required(),
});
const createSchema = schema.tailor('create');
const updateSchema = schema.tailor('update');One source of truth. No drift between schemas.
Express relationships between fields without writing validation logic. Joi handles the permutations.
const schema = Joi.object({
email: Joi.string().email(),
phone: Joi.string().pattern(/^\+?[0-9]{7,15}$/),
address: Joi.string(),
})
.or('email', 'phone') // at least one contact method
.with('phone', 'address') // phone requires address
.xor('email', 'phone'); // but not bothSeven dependency methods: .with(), .without(), .or(), .and(), .xor(), .oxor(), .nand().
Reference other fields directly in validation rules. No callbacks, no workarounds.
const schema = Joi.object({
startDate: Joi.date().required(),
endDate: Joi.date().greater(Joi.ref('startDate')).required(),
password: Joi.string().min(8).required(),
confirm: Joi.any().valid(Joi.ref('password')).required(),
});References support relative paths, value transforms, and even context variables.
Every validation failure includes the exact path, a machine-readable type code, the failing value, and the constraint that was violated. Use .annotate() to visualize errors in context.
const { error } = schema.validate(data, { abortEarly: false });
// error.details → [
// {
// message: '"age" must be greater than or equal to 18',
// path: ['age'],
// type: 'number.min',
// context: { limit: 18, value: 12, label: 'age', key: 'age' }
// }
// ]Type codes like string.email, number.min, any.required make programmatic error handling straightforward.