This page documents object schema definition, shape manipulation methods, partial/required operations, unknown key handling modes, and type inference for object types. For collection types like arrays, tuples, sets, and maps, see Collection Schemas. For schema composition via unions and intersections, see Schema Composition.
Object schemas validate JavaScript objects with typed properties. The z.object() function creates an object schema by passing a shape object where each key maps to a schema:
All properties are required by default. Optional properties are created using .optional() on the property schema:
Sources: packages/docs/content/api.mdx1062-1099 packages/zod/src/v4/classic/tests/object.test.ts5-21
Object Schema Construction Flow
The core object schema is defined in $ZodObject which maintains the shape definition and unknown key handling mode. The Classic and Mini APIs wrap this with additional methods.
Sources: packages/zod/src/v4/core/schemas.ts2363-2653 packages/zod/src/v4/classic/schemas.ts1354-1519
The $ZodObject constructor initializes object schemas with these key components:
| Component | Purpose | Location |
|---|---|---|
shape | Property schemas keyed by name | def.shape |
unknownKeys | How to handle extra keys | def.unknownKeys |
catchall | Schema for unknown keys | def.catchall |
_zod.bag.properties | JSON Schema properties | Internal |
_zod.bag.required | Required property list | Internal |
The parsing logic in $ZodObject.init() performs these steps:
unknownKeys mode (strip/strict/passthrough)Sources: packages/zod/src/v4/core/schemas.ts2363-2653
Default Behavior (strip): Unknown keys are removed from the parsed output:
Strict Mode: Throws error on unknown keys:
Passthrough Mode: Preserves unknown keys:
Catchall: Validates unknown keys against a schema:
Sources: packages/docs/content/api.mdx1102-1149 packages/zod/src/v4/classic/tests/object.test.ts91-189 packages/zod/src/v4/core/schemas.ts2496-2631
Select a subset of properties from an object schema:
The .pick() method creates a new object schema with only the specified keys. It preserves the original schema types including optional modifiers.
Sources: packages/zod/src/v4/classic/tests/pickomit.test.ts1-52 packages/zod/src/v4/classic/schemas.ts1409-1419
Remove specific properties from an object schema:
Sources: packages/zod/src/v4/classic/tests/pickomit.test.ts54-91 packages/zod/src/v4/classic/schemas.ts1420-1428
Add new properties or override existing ones:
The .extend() method silently overrides properties if keys conflict. Use .safeExtend() to throw an error on conflicts:
Sources: packages/zod/src/v4/classic/schemas.ts1381-1407 packages/zod/src/v4/core/tests/extend.test.ts4-59
Combine two object schemas, with the right schema's properties overriding the left:
The .merge() method handles optional properties correctly - if either schema has an optional property, the merged schema reflects the correct optionality based on both schemas.
Sources: packages/zod/src/v4/classic/tests/object.test.ts213-246 packages/zod/src/v4/classic/schemas.ts1454-1460
Make all properties optional:
Make specific properties optional with a mask:
The .partial() method wraps each property schema in z.optional(), except properties that are already optional or have defaults.
Sources: packages/zod/src/v4/classic/tests/partial.test.ts1-33 packages/zod/src/v4/classic/schemas.ts1430-1439
Remove optionality from all properties:
Make specific properties required with a mask:
The .required() method wraps each property in z.nonoptional() which removes the optional wrapper. For properties with .optional().default(), it removes the optional but keeps the default behavior.
Sources: packages/zod/src/v4/classic/tests/partial.test.ts34-108 packages/zod/src/v4/classic/schemas.ts1440-1452
Object schemas handle optional properties through several mechanisms:
| Pattern | Input Type | Output Type | Behavior |
|---|---|---|---|
z.string().optional() | string | undefined | string | undefined | Property can be omitted |
z.string().default("x") | string | undefined | string | Applies default if undefined |
z.string().nullable() | string | null | string | null | Allows null but not undefined |
z.string().nullish() | string | null | undefined | string | null | undefined | Both null and undefined |
When properties are omitted from input objects, their behavior depends on their optionality:
Optional keys are omitted from the output object when not provided in the input. This differs from explicitly passing undefined.
Sources: packages/zod/src/v4/classic/tests/object.test.ts165-176 packages/docs/content/api.mdx1076-1099
Access individual property schemas using the .shape property:
Extract object keys as an enum schema:
The .keyof() method returns a ZodEnum schema containing all property keys. This is useful for validating property names dynamically.
Sources: packages/zod/src/v4/classic/tests/object.test.ts28-38 packages/zod/src/v4/classic/tests/object.test.ts248-277
Define recursive object schemas using getters:
The getter pattern allows the property to reference the not-yet-fully-initialized schema. Zod lazily evaluates the getter during parsing.
For mutual recursion between multiple schemas:
Sources: packages/zod/src/v4/classic/tests/recursive-types.test.ts4-38 packages/zod/src/v4/classic/tests/recursive-types.test.ts71-120
Object type inference handles nested structures and computed types:
When working with complex object compositions:
Sources: packages/zod/src/v4/classic/tests/object.test.ts230-246 packages/zod/src/v4/classic/tests/object.test.ts279-305
The core object parsing logic resides in $ZodObject.init() at packages/zod/src/v4/core/schemas.ts2363-2653 Key implementation points:
Type Checking: Uses util.getParsedType() to verify the input is an object type (not null, array, function, etc.)
Property Iteration: Iterates through the shape keys, not the input keys, ensuring all defined properties are validated
Optional Handling: Properties wrapped in z.optional() have special handling - the optin flag marks them as optionally present in the output
Unknown Key Logic: After processing defined keys, remaining input keys are handled based on unknownKeys mode:
"strip": Ignored (default)"strict": Generate unrecognized_keys issues"passthrough": Copied to output unchangedCatchall Processing: If catchall is defined and unknownKeys allows extra keys, each unknown key is validated against the catchall schema
Deferred Properties: Properties defined with getters are evaluated lazily to support recursive schemas
Sources: packages/zod/src/v4/core/schemas.ts2363-2653 packages/zod/src/v4/core/util.ts367-369
Refresh this wiki