Skip to content

Zod vs class-validator — Evaluation ​

评估日期:2026-07-29 状态:暂不迁移,待触发条件满足后重新评估(见 ADR-0016) 2026-11-04 订正:下表有两行事实已过期(NestJS 集成 与 当前代码库),就地标注、原文保留; 订正内容见文末「订正记录(2026-11-04)」。结论(暂不迁移)与触发条件都没有变。


对比 ​

维度Zodclass-validator(当前)
类型推断✅ z.infer<typeof schema> 自动推导❌ 需手动写 interface
前端可用✅ 零依赖,轻量❌ 依赖 reflect-metadata + decorators
NestJS 集成需自定义 Pipe (2026-11-04 订正:此句已过期,Nest 12 自带 standard-schema pipe,见文末)✅ ValidationPipe 原生支持
Swagger 文档需额外配置✅ 装饰器内联 Swagger
前端表单验证✅ VeeValidate + Zod 原生集成❌ 需单独写验证规则
当前代码库0 使用 (2026-11-04 订正:此句已过期,admin 的构建配置已在用 zod 4,见文末)~100+ DTO 类,6 个子系统,30+ 装饰器文件
学习成本中(团队需学习 Zod DSL)低(团队已熟悉)
运行时性能中等中等

不迁移的原因 ​

  1. 装饰器体系已成熟:WalnutAdminDecoratorField* 将 validation + transformation + Swagger docs 统一到一个装饰器中,实现了类似 Zod "单一声明"的体验
  2. 迁移成本太高:涉及 16 个 guard、中件间/interceptor 层、libs/decorators/ 6 个子系统、~100+ DTO 类
  3. 前端表单验证复用不是当前痛点:要发挥 Zod 的前后端复用优势,需要前端接入 VeeValidate + Zod,目前没有这个需求
  4. 避免双范式并存:逐步迁移意味着长期维护 class-validator 和 Zod 两套体系

触发条件(何时重新评估) ​

触发条件说明
前端接入 VeeValidate + ZodDRY 验证变为可实现
新建 NestJS 绿场模块可在新模块试点 Zod,无需迁移旧代码
class-validator 停止维护或不兼容 NestJS 新版本强制迁移
3+ 个前端应用共享同一后端共享 schema 的 ROI 提高

订正记录(2026-11-04) ​

上表有两行事实性陈述已经过期,就地标注、原文保留(判断本身没被推翻 —— 结论仍是「暂不迁移」, 变的是那两条成本/现状的依据):

  1. 「NestJS 集成:需自定义 Pipe」不再成立。 NestJS 12 原生支持 Standard Schema (@Body({ schema }) + StandardSchemaValidationPipe,同一份 schema 还能驱动 OpenAPI), 接 Zod 不需要自己写 pipe。也就是说原判断里「Zod 要多一层胶水」这条成本已经消失,剩下的成本是 「存量 DTO 迁移 + 长期双范式并存」—— 正是本页「不迁移的原因」第 2 / 4 条,结论不受影响。
  2. 「当前代码库:0 使用」不再成立。 admin 已经在用 zod 4:依赖在 catalog 里 (pnpm-workspace.yaml 的 zod 一行,admin 侧 package.json 以 catalog: 引用), 实际消费者是构建期环境变量校验(apps/admin/build/vite/config/env.{development,stage,prod}.ts 写 import { z } from 'zod/v4',同目录 shared.ts 用 from 'zod';都是 zod 4 的 API)。 准确现状是**「前端构建配置在用、后端 DTO 仍未用」,不是「全仓 0 使用」;两者的区别正是 「前后端共享 schema」这条触发条件的现状 —— 前端还没把 zod 用到表单/接口契约**上。

订正只覆盖这两条事实。触发条件表与「不迁移的原因」按现状仍然成立,重新评估时以这一节为准, 别再引用上表那两个格子里的旧值。

参考 ​

基于 MIT 许可发布