On this Guide
- Lesson 06: Schema Composition with Merge, Extend, Pick, and Omit
- Lesson 07: Refinement, superRefine, and Custom Validators
- Lesson 08: Discriminated Unions and Tagged Types
- Lesson 09: Transforming and Preprocessing Data
- Lesson 10: Working with Records, Maps, Sets, and Enums
- Lesson 11: Async Validation with Promises
- Lesson 12: Reusable Schemas Across Frontend and Backend
Why Transform or Preprocess?
Sometimes raw input isnβt in the shape you want:
- A date string that needs to become a
Dateobject - A number stored as a string
- A string that needs trimming or formatting
Zod offers .transform() and .preprocess() to fix, convert, or sanitize input during validation.
Using transform()
Use .transform() after validation to shape or derive new values.
const schema = z.string().transform((val) => val.trim().toUpperCase());
const result = schema.parse(" hello ");
// β "HELLO"
You can also change the output type:
const NumSchema = z.string().transform((val) => parseInt(val));
type Result = z.infer<typeof numschema>;
// Result is now `number`, not `string`
Using preprocess()
Use .preprocess() to manipulate values before validation happens.
Example: Accept a number or a string and turn it into a number before validating:
const schema = z.preprocess((val) => Number(val), z.number().min(0));
schema.parse("42"); // β
42
schema.parse(42); // β
42
schema.parse("abc"); // β Not a number
This is great for working with:
- Query strings
- Form data
- Environment variables
Differences Between transform and preprocess
| Feature | .transform() |
.preprocess() |
|---|---|---|
| Runs after validation | β | β |
| Runs before validation | β | β |
| Can change output type | β | β |
| Use case | Reformat/derive | Sanitize/parse raw input |
Practical Examples
1. Convert date string to Date object
const DateSchema = z
.string()
.refine((val) => !isNaN(Date.parse(val)), {
message: "Invalid date format",
})
.transform((val) => new Date(val));
2. Trim and lowercase email
const EmailSchema = z
.string()
.email()
.transform((val) => val.trim().toLowerCase());
3. Parse string to number and validate
const AgeSchema = z.preprocess(
(val) => Number(val),
z.number().int().positive()
);
Summary
- Use
.transform()to clean or reformat values after validation - Use
.preprocess()to sanitize input before validation - Both are powerful tools to adapt real-world input to strict, type-safe schemas
- Great for working with forms, APIs, and config data
Next: Lesson 10 β Working with Records, Maps, Sets, and Enums in Zod
Master the Code, Be the Guru!