Zod is one of the best things that happened in the JavaScript community and become indispensable for me alongide tools like lodash, vite, pnpm and prettier.
Using zod Functions you can easily isolate your business logic and reuse in different contexts like a classic Express app, a Serverless function in AWS Lambda or Netlify Functions, a Next.js route, Server Action or Remix API route and map the errors to return an appropriate response on each framework.
The schemas are easily to understand, create and edit. The .coerse
easily transforms your params like path or query params. You can add async validations using .refine
and then .parseAsync
, document fields and schemas using .describe
and even edit the input before validating with .pipe
.
Way simpler and more powerful than the verbose Nest.js Pipes and class-validator for example, creating custom Schema directives in your GraphQL type definitions, or verbose JSON Schemas with ajv.
import { z } from "zod"
const numberParam = z.coerce.number().int().min(0).default(0)
const addNumbers = z
.function()
.args(
z.object({
a: numberParam,
b: numberParam,
})
)
.implement(({ a, b }) => {
return a + b
})
const input: any = { a: "1", b: "2" }
console.log(addNumbers(input))
// 3
If you are using a monorepo structure like Nx or Turbo you can share the input schemas and typings when needed between different implementations or your server and client using libs or use a private NPM repository.
If you are using react-hook-form, the Zod resolver will be useful.
With the proper JSDoc comments, if you are using VS Code you might not even need TypeScript and rely heavily on zod infered types.