Skip to main content

Overview

The .transform() method allows you to transform validated data into a different shape or type. Transformations run after validation succeeds, ensuring you always work with valid data.

Signature

Output
required
The validated output data from the schema
RefinementCtx
required
Context object with addIssue() method for adding validation errors
Returns: ZodPipe<Schema, ZodTransform<NewOutput, Output>>

Basic Usage

Simple Transformations

String Transformations

Async Transformations

Transforms can be asynchronous:
Async transforms must use parseAsync() or safeParseAsync(). Calling parse() with an async transform will throw an error.

Adding Validation During Transform

Use the context object to add validation errors:

Using z.NEVER

Return z.NEVER to exclude a value from the output type:

Object Transformations

Type Coercion in Objects

Reshaping Objects

Chaining Transformations

You can chain multiple transformations:

Combining with Refinements

Refinement Before Transform

Validate before transforming:

Transform Then Refine

Transform, then validate the result:

Short-Circuiting on Errors

By default, transforms don’t run if validation fails:

Context Methods

ctx.addIssue()

Add a validation error:

Short Form

Use a string for simple custom messages:

Continuing After Errors

By default, adding an issue stops further validation. Set continue: true to continue:

Common Patterns

JSON Parsing

Trimming and Normalizing

Default Values with Transform

Computing Derived Fields

Async Data Enrichment

Encoding Errors

Transformations are unidirectional by default. Use .encode() will throw:
For bidirectional transformations, use z.codec().

Type Inference

Transforms affect type inference:

Error Handling Examples

Transform Validation Errors

Best Practices

Transform after validation

Always validate your data before transforming it. Transformations assume valid input.

Use meaningful transformations

Transformations should have a clear purpose. Don’t use them for side effects.

Handle errors gracefully

Use ctx.addIssue() for expected error cases. Let unexpected errors throw naturally.

Consider performance

Async transforms and complex transformations can impact performance. Cache results when possible.

Type safety matters

Let TypeScript infer types when possible. Explicit type annotations can catch transformation errors.

See Also

  • Pipe - Chain schemas together
  • Refine - Custom validation
  • Coerce - Type coercion
  • Codec - Bidirectional transformations