# How to Use Zod's Mask Method for Partial Field Handling

> Master Zod's mask method to selectively handle partial fields. Learn how to update specific schema fields using truthy masks for efficient data validation.

- Repository: [Colin McDonnell/zod](https://github.com/colinhacks/zod)
- Tags: how-to-guide
- Published: 2026-02-23

---

**TLDR:** Supply an object mask with truthy values (e.g., `{ name: true, age: true }`) to Zod's `partial()`, `required()`, `pick()`, or `omit()` methods to selectively transform only those specific fields while leaving the rest of the schema untouched.

The mask argument in Zod enables precise, field-level control over object schema transformations without affecting the entire shape. Implemented in the colinhacks/zod repository, this feature allows you to target specific properties for partial handling while maintaining strict type safety through runtime key validation. Understanding how to use Zod's mask method for partial field handling is essential for building flexible, composable validation schemas that adapt to complex input requirements.

## Understanding the Mask Type Definition

At the core of this functionality lies the **Mask** type defined in `packages/zod/src/v4/core/util.ts#L100`. This type serves as a simple record where keys represent the fields you want to transform and values must be truthy (typically `true`) to activate the transformation.

```typescript
export type Mask<Keys extends PropertyKey> = { [K in Keys]?: true };

```

Any falsy value assigned to a key is ignored during processing, which allows you to construct masks programmatically without pre-filtering your configuration objects.

## Internal Implementation of Partial with Masks

The `partial` utility function in `packages/zod/src/v4/core/util.ts#L709-L756` handles the mask logic internally. When you provide a mask object, the function iterates over each key, validates its existence in the original schema shape, and—only if the value is truthy—wraps that property in a `ZodOptional` schema.

```typescript
export function partial(
  Class: SchemaClass<schemas.$ZodOptional> | null,
  schema: schemas.$ZodObject,
  mask: object | undefined
): any {
  // ... schema processing logic ...
  if (mask) {
    for (const key in mask) {
      if (!(key in oldShape)) {
        throw new Error(`Unrecognized key: "${key}"`);
      }
      if (!(mask as any)[key]) continue;           // falsy → ignore
      shape[key] = Class
        ? new Class({ type: "optional", innerType: oldShape[key]! })
        : oldShape[key]!;
    }
  } else {
    // no mask → every key becomes optional
    for (const key in oldShape) { /* ... */ }
  }
  // ...
}

```

If you omit the mask argument entirely, the function defaults to making every property in the object optional.

## Public API Wiring in ZodObject

The public-facing `partial()` method on `ZodObject` instances delegates to this utility function. In `packages/zod/src/v4/classic/schemas.ts#L82-L84`, the method signature forwards your mask argument directly to the core implementation:

```typescript
inst.partial = (...args: any[]) => util.partial(ZodOptional, inst, args[0] as object);

```

The same pattern applies to `required()`, `pick()`, and `omit()`, all of which accept an optional mask argument for selective field handling.

## Practical Examples of Using Masks

### Selective Partial Conversion

Instead of making every field optional, use a mask to target specific properties. This example from the test suite demonstrates making only `age`, `field`, and `name` optional while keeping `country` required:

```typescript
import { z } from "zod";

const user = z.object({
  name: z.string(),
  age: z.number().optional(),
  field: z.string().optional().default("asdf"),
  country: z.string(),
});

const masked = user
  .partial({ age: true, field: true, name: true })
  .strict();

// masked.shape.name is now ZodOptional<ZodString>
// masked.shape.country remains ZodString (required)

masked.parse({ country: "US" }); // ✅ passes

```

*Source:* `packages/zod/src/v4/classic/tests/partial.test.ts#L10-L27`

### Ignoring Falsy Values in Masks

The mask implementation skips falsy values, allowing you to conditionally include fields without breaking the schema construction:

```typescript
const shouldMakeOptional = false;

const partialIgnore = user.partial({ 
  name: true, 
  country: shouldMakeOptional // false → ignored
}).strict();

// Only 'name' becomes optional; 'country' stays required
partialIgnore.shape.country instanceof z.ZodString; // true

```

*Source:* `packages/zod/src/v4/classic/tests/partial.test.ts#L29-L44`

### Converting Optional Fields to Required

You can use the mask argument with the `required()` method to make specific optional fields mandatory again:

```typescript
const reqMask = user.required({ age: true }).strict();

// age is now required (ZodNonOptional)
// field retains its default value behavior
reqMask.shape.age instanceof z.ZodNonOptional; // true

```

*Source:* `packages/zod/src/v4/classic/tests/partial.test.ts#L79-L92`

### Picking and Omitting Fields with Masks

The mask pattern extends to schema filtering. Use `pick()` to retain only specified fields or `omit()` to remove specific properties:

```typescript
// Retain only name and age
const picked = user.pick({ name: true, age: true });
// picked.shape contains only name and age

// Remove the field property
const omitted = user.omit({ field: true });
// omitted.shape excludes field but keeps name, age, and country

```

*Source:* `packages/zod/src/v4/core/util.ts#L593-L648`

## Summary

- **Supply a mask object** with `true` values to `partial()`, `required()`, `pick()`, or `omit()` for selective field transformation instead of schema-wide changes.
- **Runtime validation** occurs in `util.partial`, which throws an `Unrecognized key` error if you attempt to mask a property that doesn't exist in the original shape.
- **Falsy values are ignored** during mask processing, enabling dynamic mask construction where conditions can disable certain fields without error.
- **Consistent API pattern** across object methods allows you to compose complex schema transformations while maintaining type safety and clear intent.

## Frequently Asked Questions

### What happens if I include a non-existent key in the mask?

Zod throws an `Unrecognized key` error during schema construction. The `util.partial` function explicitly checks `if (!(key in oldShape))` before processing each mask key to prevent typos and ensure type safety.

### Can I use masks with methods other than partial()?

Yes, the mask argument works with `required()`, `pick()`, and `omit()` methods on `ZodObject` instances. All three methods follow the same implementation pattern in [`packages/zod/src/v4/core/util.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/util.ts), accepting a `Mask` type to target specific fields while preserving the rest of the schema.

### Why does Zod ignore falsy values in the mask?

The implementation includes the check `if (!(mask as any)[key]) continue` to skip falsy entries. This design allows you to build masks programmatically using boolean variables or conditions without needing to filter out `false` values beforehand, making dynamic schema construction cleaner and more intuitive.

### How does partial() with a mask differ from calling partial() without arguments?

Calling `partial()` without arguments makes **every** field in the object optional by iterating over `oldShape` directly. Providing a mask makes **only** the specified fields optional, leaving all other properties with their original required or optional status intact.