Overview
Transformations allow you to modify data after validation. The.transform() method runs after all validations pass, converting the data to a different shape or type.
Basic Transformation
Use.transform() to modify validated data:
packages/zod/src/v4/classic/tests/transform.test.ts:86-91:
Transformation Signature
Frompackages/zod/src/v4/classic/schemas.ts:114-116, the .transform() method signature:
Transformations receive two parameters:
arg- The validated output valuectx- A context object for adding issues
Common Use Cases
Type Coercion
Convert strings to numbers:packages/zod/src/v4/classic/tests/transform.test.ts:94-102:
String Manipulation
Data Normalization
Object Reshaping
Async Transformations
Transformations can be asynchronous:packages/zod/src/v4/classic/tests/transform.test.ts:104-113:
Chaining Transformations
Multiple transformations can be chained:packages/zod/src/v4/classic/tests/transform.test.ts:186-192:
Error Handling in Transformations
Use the context object to add validation errors:packages/zod/src/v4/classic/tests/transform.test.ts:4-28:
Using z.NEVER
Frompackages/zod/src/v4/classic/tests/transform.test.ts:62-83:
Returning
z.NEVER from a transformation signals that validation should fail, and it also narrows the output type appropriately.Input vs Output Types
Transformations change the output type while keeping the input type:Practical Examples
Date Parsing
JSON Parsing
URL Slug Generation
Form Data Processing
API Response Transformation
Transformation Order
Transformations run AFTER all validations:packages/zod/src/v4/classic/tests/transform.test.ts:194-200:
Transformations vs Defaults
Understand the difference:Transformations vs Refinements
- Refinements (
.refine()) - Add validation, don’t change data - Transformations (
.transform()) - Modify data after validation
Performance Considerations
Transformations add overhead to parsing. For high-performance scenarios, consider whether you really need to transform during validation or if it’s better to transform separately.
Combining with Pipes
Transformations can be combined with pipes for complex data flows:Best Practices
- Keep transformations simple - Complex logic is hard to debug
- Use transformations for data coercion - Converting types, normalizing formats
- Handle errors explicitly - Use
ctx.addIssue()for validation failures - Consider performance - Avoid expensive operations in transforms
- Type safety - TypeScript will infer the output type correctly
Common Gotchas
Async in Sync Context
Returning Undefined
Next Steps
- Learn about Refinements for custom validation
- Explore Parsing to understand when transformations run
- Master Type Inference to work with transformed types