valrs

Primitives

String, number, boolean, and other primitive type schemas

Primitives

valrs provides schemas for all JavaScript primitive types with chainable validation methods.

String

Create string schemas with v.string():

import { v } from 'valrs';
 
const schema = v.string();
 
schema.parse('hello'); // 'hello'
schema.parse(123);     // throws ZodError

String Methods

MethodDescription
.min(n)Minimum length
.max(n)Maximum length
.length(n)Exact length
.email()Valid email format
.url()Valid URL format
.uuid()Valid UUID format
.cuid()Valid CUID format
.cuid2()Valid CUID2 format
.ulid()Valid ULID format
.regex(re)Match regular expression
.includes(str)Contains substring
.startsWith(str)Starts with prefix
.endsWith(str)Ends with suffix
.datetime()ISO 8601 datetime
.ip()Valid IP address (v4 or v6)
.trim()Trim whitespace (transform)
.toLowerCase()Convert to lowercase (transform)
.toUpperCase()Convert to uppercase (transform)

String Examples

import { v } from 'valrs';
 
// Email validation
const email = v.string().email();
email.parse('user@example.com'); // valid
email.parse('invalid');          // throws
 
// URL validation
const url = v.string().url();
url.parse('https://example.com'); // valid
 
// UUID validation
const uuid = v.string().uuid();
uuid.parse('550e8400-e29b-41d4-a716-446655440000'); // valid
 
// CUID validation
const cuid = v.string().cuid();
cuid.parse('cjld2cjxh0000qzrmn831i7rn'); // valid
 
// CUID2 validation
const cuid2 = v.string().cuid2();
cuid2.parse('tz4a98xxat96iws9zmbrgj3a'); // valid
 
// ULID validation
const ulid = v.string().ulid();
ulid.parse('01ARZ3NDEKTSV4RRFFQ69G5FAV'); // valid
 
// Length constraints
const username = v.string().min(3).max(20);
username.parse('alice'); // valid
username.parse('ab');    // throws: too short
 
// Regex pattern
const slug = v.string().regex(/^[a-z0-9-]+$/);
slug.parse('my-blog-post'); // valid
 
// Transforms
const normalized = v.string().trim().toLowerCase();
normalized.parse('  HELLO  '); // 'hello'
 
// Datetime validation
const datetime = v.string().datetime();
datetime.parse('2024-01-15T10:30:00Z'); // valid
 
// IP address
const ip = v.string().ip();
ip.parse('192.168.1.1');  // valid (IPv4)
ip.parse('::1');          // valid (IPv6)

Custom Error Messages

const email = v.string({
  required_error: 'Email is required',
  invalid_type_error: 'Email must be a string',
}).email({ message: 'Invalid email address' });

Number

Create number schemas with v.number():

import { v } from 'valrs';
 
const schema = v.number();
 
schema.parse(42);      // 42
schema.parse(3.14);    // 3.14
schema.parse('42');    // throws ZodError

Number Methods

MethodDescription
.gt(n)Greater than
.gte(n) or .min(n)Greater than or equal
.lt(n)Less than
.lte(n) or .max(n)Less than or equal
.int()Must be integer
.positive()Must be positive
.nonnegative()Must be non-negative
.negative()Must be negative
.nonpositive()Must be non-positive
.multipleOf(n) or .step(n)Must be multiple of n
.finite()Must be finite (not Infinity)
.safe()Must be safe integer

Number Examples

import { v } from 'valrs';
 
// Integer validation
const age = v.number().int().min(0).max(150);
age.parse(25);   // valid
age.parse(25.5); // throws: not an integer
 
// Positive numbers
const price = v.number().positive();
price.parse(9.99);  // valid
price.parse(-5);    // throws
 
// Range validation
const percentage = v.number().min(0).max(100);
percentage.parse(75); // valid
 
// Greater than / less than
const temperature = v.number().gt(-273.15).lt(1000);
temperature.parse(20); // valid
 
// Multiple of
const even = v.number().multipleOf(2);
even.parse(4); // valid
even.parse(3); // throws
 
// Safe integers
const safeInt = v.number().int().safe();
safeInt.parse(9007199254740991);  // valid (Number.MAX_SAFE_INTEGER)
safeInt.parse(9007199254740992);  // throws
 
// Finite numbers
const finite = v.number().finite();
finite.parse(42);       // valid
finite.parse(Infinity); // throws

BigInt

Create bigint schemas with v.bigint():

import { v } from 'valrs';
 
const schema = v.bigint();
 
schema.parse(100n);  // 100n
schema.parse(100);   // throws ZodError
const largeNumber = v.bigint();
largeNumber.parse(9007199254740993n); // valid

Boolean

Create boolean schemas with v.boolean():

import { v } from 'valrs';
 
const schema = v.boolean();
 
schema.parse(true);   // true
schema.parse(false);  // false
schema.parse(1);      // throws ZodError
schema.parse('true'); // throws ZodError

Date

Create date schemas with v.date():

import { v } from 'valrs';
 
const schema = v.date();
 
schema.parse(new Date());          // valid
schema.parse('2024-01-15');        // throws (use v.coerce.date() for strings)
const futureDate = v.date();
futureDate.parse(new Date()); // valid

Null, Undefined, Void

import { v } from 'valrs';
 
// Null only
const nullSchema = v.null();
nullSchema.parse(null);      // null
nullSchema.parse(undefined); // throws
 
// Undefined only
const undefinedSchema = v.undefined();
undefinedSchema.parse(undefined); // undefined
undefinedSchema.parse(null);      // throws
 
// Void (undefined)
const voidSchema = v.void();
voidSchema.parse(undefined); // undefined

Any, Unknown, Never

import { v } from 'valrs';
 
// Any - no validation, any value passes
const anySchema = v.any();
anySchema.parse('anything'); // 'anything'
anySchema.parse(123);        // 123
anySchema.parse(null);       // null
 
// Unknown - like any, but type-safe
const unknownSchema = v.unknown();
unknownSchema.parse('anything'); // 'anything'
 
// Never - always fails
const neverSchema = v.never();
neverSchema.parse('anything'); // throws

Coercion

Use v.coerce to automatically convert values before validation:

import { v } from 'valrs';
 
// Coerce to string
v.coerce.string().parse(123);     // '123'
v.coerce.string().parse(true);    // 'true'
v.coerce.string().parse(null);    // 'null'
v.coerce.string().parse(undefined); // 'undefined'
 
// Coerce to number
v.coerce.number().parse('42');    // 42
v.coerce.number().parse('3.14');  // 3.14
v.coerce.number().parse('abc');   // throws (NaN is not valid)
 
// Coerce to boolean
v.coerce.boolean().parse('true'); // true (any truthy value)
v.coerce.boolean().parse(1);      // true
v.coerce.boolean().parse(0);      // false
v.coerce.boolean().parse('');     // false
 
// Coerce to date
v.coerce.date().parse('2024-01-15');           // Date object
v.coerce.date().parse(1705276800000);          // Date from timestamp
 
// Coerce to bigint
v.coerce.bigint().parse('100');   // 100n
v.coerce.bigint().parse(100);     // 100n

Coercion Types

CoercerDescription
v.coerce.string()Converts to string using String()
v.coerce.number()Converts to number using Number(), fails on NaN
v.coerce.boolean()Converts to boolean using Boolean()
v.coerce.bigint()Converts to bigint using BigInt()
v.coerce.date()Converts to Date using new Date()

Coercion with Validation

Coercion happens before validation methods are applied:

const age = v.coerce.number().int().min(0).max(150);
 
age.parse('25');  // 25 (coerced from string, then validated)
age.parse('abc'); // throws (can't coerce to number)

Integer Types

valrs provides specialized integer schemas for specific bit widths:

import { v } from 'valrs';
 
// 32-bit signed integer (-2147483648 to 2147483647)
const int32 = v.int32();
int32.parse(42);           // valid
int32.parse(2147483648);   // throws (out of range)
 
// 64-bit signed integer
const int64 = v.int64();
 
// 32-bit unsigned integer (0 to 4294967295)
const uint32 = v.uint32();
uint32.parse(42);          // valid
uint32.parse(-1);          // throws (negative)
 
// 64-bit unsigned integer
const uint64 = v.uint64();
 
// 32-bit floating point
const float32 = v.float32();
 
// 64-bit floating point
const float64 = v.float64();

Literals

Create schemas for literal values:

import { v } from 'valrs';
 
// String literal
const hello = v.literal('hello');
hello.parse('hello'); // 'hello'
hello.parse('world'); // throws
 
// Number literal
const answer = v.literal(42);
answer.parse(42); // 42
 
// Boolean literal
const yes = v.literal(true);
yes.parse(true);  // true
yes.parse(false); // throws
 
// BigInt literal
const bigLiteral = v.literal(100n);

Next Steps

On this page