Skip to content

joi

The most powerful schema description language and data validator for JavaScript

joi logo

Get started in seconds

console
npm install joi
console
yarn add joi
console
pnpm add joi
js
import 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,
});

Built for real-world validation

1. Schema Variants with .alter() + .tailor()

Define one schema. Produce specialized versions for different contexts — like separate validation for GET vs POST — without duplicating anything.

js
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.

2. Declarative Field Dependencies

Express relationships between fields without writing validation logic. Joi handles the permutations.

js
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 both

Seven dependency methods: .with(), .without(), .or(), .and(), .xor(), .oxor(), .nand().

3. Cross-Field References

Reference other fields directly in validation rules. No callbacks, no workarounds.

js
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.

4. Rich, Actionable Errors

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.

js
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.

Deploys by Netlify