Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
create
✓ import { create } from 'vest';
✗ const create = require('vest');
Vest is primarily designed for ESM. CommonJS `require` can be problematic since v4 deprecated default exports and v6 returns a Suite Object, not a function.
test
✓ import { test } from 'vest';
✗ import vest, { test } from 'vest';
Since Vest v4, default imports were removed for better tree-shaking. Always use named imports for core utilities like `test`.
enforce
✓ import { enforce } from 'vest';
✗ const { enforce } = require('vest');
The `enforce` assertion library is a named export. Ensure your environment supports ESM imports.
memo
✓ import { memo } from 'vest/memo';
The `memo` utility, for memoizing validation logic, was moved to its own module in v6.
SuiteSerializer
✓ import { SuiteSerializer } from 'vest/exports/SuiteSerializer';
For SSR and hydration, `SuiteSerializer` is imported from a specific subpath.
This quickstart demonstrates how to define a Vest validation suite with synchronous and asynchronous tests, including conditional logic, and how to execute the suite and interpret its results for a typical signup form.
import { create, test, enforce } from 'vest';
// Simulate an async API call, e.g., checking if a username exists
const doesUsernameExist = async (username: string): Promise<boolean> => {
return new Promise(resolve => {
setTimeout(() => {
resolve(username === 'admin'); // 'admin' is taken
}, 500);
});
};
interface FormData {
username?: string;
email?: string;
password?: string;
confirmPassword?: string;
}
const signupSuite = create((data: FormData = {}) => {
test('username', 'Username is required', () => {
enforce(data.username).isNotBlank();
});
test('username', 'Username must be at least 3 characters long', () => {
enforce(data.username).longerThanOrEquals(3);
});
// Async validation
test('username', 'Username is already taken', async () => {
if (data.username) {
await enforce(await doesUsernameExist(data.username)).isFalsy();
}
});
test('email', 'Email is required', () => {
enforce(data.email).isNotBlank();
});
test('email', 'Email must be valid', () => {
enforce(data.email).isEmail();
});
test('password', 'Password is required', () => {
enforce(data.password).isNotBlank();
});
test('password', 'Password must be at least 8 characters long', () => {
enforce(data.password).longerThanOrEquals(8);
});
// Conditional validation: only run if password is valid and present
if (data.password && signupSuite.get().hasErrors('password') === false) {
test('confirmPassword', 'Passwords do not match', () => {
enforce(data.confirmPassword).equals(data.password);
});
}
});
async function validateForm(formData: FormData) {
console.log('Validating with data:', formData);
const result = await signupSuite.run(formData);
console.log('Validation Results:');
console.log(' isValid:', result.isValid());
console.log(' hasErrors:', result.hasErrors());
console.log(' getErrors:', result.getErrors());
console.log(' getWarnings:', result.getWarnings());
if (!result.isValid()) {
console.log('Validation failed!');
} else {
console.log('Validation passed!');
}
}
// Example usage
validateForm({ username: '', email: 'test@example.com', password: 'password123', confirmPassword: 'password123' });
validateForm({ username: 'john', email: 'john@example.com', password: 'short', confirmPassword: 'short' });
validateForm({ username: 'admin', email: 'admin@example.com', password: 'password123', confirmPassword: 'password123' });
validateForm({ username: 'newUser', email: 'new@example.com', password: 'supersecurepassword', confirmPassword: 'supersecurepassword' });
Errors
Common errors & fixes
TypeError: suite is not a function
Attempting to call the result of `create` directly as a function, which was the behavior in Vest v5, but `create` returns a Suite Object in v6.
fixCall the `.run()` method on the suite object: `const result = mySuite.run(data);`.
ReferenceError: test is not defined
`test` was not correctly imported as a named export. This often happens if attempting a default import (e.g., `import vest from 'vest'`) or if `test` is simply missing from the named import.
fixEnsure `test` is imported as a named export: `import { create, test, enforce } from 'vest';`. Cannot read properties of undefined (reading 'isNotBlank')
The `enforce` assertion was called with an `undefined` value, usually when `data.fieldName` is missing or `null` in the input, and Vest attempts to apply an assertion that expects a defined value.
fixEnsure the field exists or add conditional checks before enforcing: `if (data.username) { enforce(data.username).isNotBlank(); }` or handle `undefined` within your schema definition. Asynchronous validation is not waiting for completion or result is premature.
Forgetting to `await` the result of `suite.run()` when the suite contains asynchronous tests, or not handling the Promise-like nature of the v6 `SuiteResult` object.
fixAlways `await` the result when working with async validations: `const result = await mySuite.run(data);`.
Audit
Dependencies
No dependency data recorded yet.