Skip to main content

.nullable()

Makes a schema accept null in addition to its base type.
import { z } from 'zod';

const schema = z.string().nullable();

schema.parse('hello');     // 'hello'
schema.parse(null);        // null
schema.parse(undefined);   // throws error

Type Inference

The .nullable() modifier affects both input and output types:
const schema = z.string().nullable();

type Input = z.input<typeof schema>;   // string | null
type Output = z.output<typeof schema>; // string | null

Unwrapping

You can remove the nullable wrapper using .unwrap():
const nullable = z.string().nullable();
const base = nullable.unwrap(); // ZodString

In Object Schemas

const User = z.object({
  name: z.string(),
  middleName: z.string().nullable(),
});

User.parse({
  name: 'John',
  middleName: null,        // Valid
});

User.parse({
  name: 'John',
  middleName: 'Robert',    // Valid
});

User.parse({
  name: 'John',
  // middleName is required, cannot be omitted
}); // throws error
.nullable() does not make a field optional in objects. The field must still be present, but can be null.

.nullish()

A convenience method that combines .optional() and .nullable(), making a schema accept null, undefined, or the base type.
const schema = z.string().nullish();

// Equivalent to:
const equivalent = z.string().nullable().optional();

schema.parse('hello');     // 'hello'
schema.parse(null);        // null
schema.parse(undefined);   // undefined

Type Inference

const schema = z.string().nullish();

type Input = z.input<typeof schema>;   // string | null | undefined
type Output = z.output<typeof schema>; // string | null | undefined

In Object Schemas

const User = z.object({
  name: z.string(),
  nickname: z.string().nullish(),
});

User.parse({ name: 'John' });                       // Valid - nickname omitted
User.parse({ name: 'John', nickname: undefined });  // Valid
User.parse({ name: 'John', nickname: null });       // Valid
User.parse({ name: 'John', nickname: 'Johnny' });   // Valid

Use Cases

  • .nullable(): Use for database fields that can be NULL but must be present
  • .nullish(): Use for optional fields that could also be explicitly set to null

Chaining Examples

// Nullable with default
const schema1 = z.string().nullable().default('hello');
schema1.parse(undefined); // 'hello'
schema1.parse(null);      // null (default not applied to null)

// Nullable with catch
const schema2 = z.string().nullable().catch('fallback');
schema2.parse(123);       // 'fallback' (invalid input)
schema2.parse(null);      // null (valid input)

// Nullish with refinement
const schema3 = z.string()
  .nullish()
  .refine(val => val !== null, 'Cannot be null');

schema3.parse(undefined);  // undefined (valid)
schema3.parse('hello');    // 'hello' (valid)
schema3.parse(null);       // throws error

Implementation Note

// .nullish() is implemented as:
.nullish() {
  return this.nullable().optional();
}

// This means it creates a nested structure:
z.string().nullish()
// Is equivalent to:
z.optional(z.nullable(z.string()))

Build docs developers (and LLMs) love