1 puntos por GN⁺ 2025-05-20 | 1 comentarios | Compartir por WhatsApp
  • Zod 4 se publica como versión estable tras 1 año de desarrollo, corrigiendo los límites de diseño de Zod 3 y mejorando significativamente el rendimiento, el tamaño del bundle y la eficiencia de compilación de TypeScript
  • Zod 3, lanzado en mayo de 2021, creció desde 2,700 estrellas en GitHub y 600 mil descargas semanales hasta las actuales 37.8k estrellas y 31 millones de descargas semanales; después de 24 versiones menores, las mejoras importantes ya requerían cambios incompatibles
  • En los benchmarks, el parsing de strings es 14 veces más rápido, el de arrays 7 veces más rápido y el de objetos 6.5 veces más rápido; las instanciaciones de tipos en tsc también bajaron de más de 25,000 a unas 175 en un ejemplo simple
  • El tamaño del bundle principal, medido con gzip, se redujo de 12.47kb en Zod 3 a 5.36kb en la versión normal de Zod 4, y Zod Mini, con una API funcional compatible con tree shaking, baja hasta 1.88kb
  • Entre las nuevas funciones se incluyen conversión a JSON Schema, registros de metadatos, inferencia de tipos de objetos recursivos, internacionalización, pretty-printing de errores, tipos template literal, z.stringbool(), un parámetro error unificado y mejoras en z.discriminatedUnion()

Por qué Zod 4 es una nueva versión major

  • Zod 4 alcanzó la versión estable tras 1 año de desarrollo activo, con una base más rápida, más ligera y más eficiente para tsc, sobre la que se implementaron funciones muy solicitadas desde hace tiempo
  • Zod v3.0 se lanzó en mayo de 2021, cuando tenía 2,700 estrellas en GitHub y 600 mil descargas semanales
  • Actualmente Zod registra 37.8k estrellas en GitHub y 31 millones de descargas semanales
    • Hace 6 semanas, cuando salió la beta, tenía 23 millones de descargas semanales
  • Tras acumular 24 versiones menores, la base de código de Zod 3 llegó a su límite, y las funciones y mejoras más pedidas requerían cambios incompatibles
  • Zod 4 cerró 9 de los 10 issues públicos con más votos

Rendimiento de parsing y eficiencia de compilación en TypeScript

  • Zod 4 ofrece benchmarks que pueden ejecutarse directamente desde el repositorio
  • Mejoras en rendimiento de parsing:
    • Parsing de strings: 14 veces más rápido
    • Parsing de arrays: 7 veces más rápido
    • Parsing de objetos: 6.5 veces más rápido
  • El benchmark de parsing de objetos ejecuta el Moltar validation library benchmark
  • Según tsc --extendedDiagnostics, en la compilación de un archivo simple las instanciaciones de tipos se reducen drásticamente
    • Usando "zod/v3": más de 25,000 veces
    • Usando "zod/v4": alrededor de 175 veces
  • Zod 4 rediseñó y simplificó los genéricos de ZodObject y otras clases de schema para evitar la explosión de instanciaciones
  • El patrón de encadenar repetidamente .extend() y .omit() tardaba 4000ms en compilar en Zod 3, y agregar otra llamada a .extend() podía provocar el error "Possibly infinite"
  • El mismo patrón compila en 400ms en Zod 4, siendo 10 veces más rápido
  • En el futuro, al usarse junto con el compilador tsgo, el rendimiento del editor con Zod 4 podría escalar mejor a schemas y codebases más grandes

Tamaño del bundle y Zod Mini

  • Se comparó el tamaño del bundle principal empaquetando con rollup un script simple de validación con z.boolean()
  • Tamaño del bundle principal con gzip:
    • Zod 3: 12.47kb
    • Zod 4 versión normal: 5.36kb
  • El bundle principal de la versión normal de Zod 4 es aproximadamente 57% más pequeño que el de Zod 3, una reducción de 2.3 veces
  • La API centrada en métodos de Zod es difícil de optimizar con tree shaking por naturaleza, y hasta un script simple con z.boolean() arrastra implementaciones no usadas como .optional() o .array()
  • Zod Mini ofrece una API funcional con tree shaking que corresponde 1:1 con zod
    • Donde Zod usa métodos, Zod Mini normalmente usa funciones envoltorio
    • Los métodos de parsing son iguales en Zod y Zod Mini
    • Se agrega refinamiento con el método genérico .check()
  • Zod normal sigue siendo la recomendación para la mayoría de los casos de uso, y los proyectos con restricciones de tamaño de bundle inusualmente estrictas pueden considerar Zod Mini
  • Usando zod/mini, el tamaño del bundle con gzip es de 1.88kb
    • Frente a Zod 3, eso representa una reducción de 85% y 6.6 veces menos
    • Tabla comparativa: Zod 3 12.47kb, Zod 4 normal 5.36kb, Zod 4 Mini 1.88kb
  • Más detalles pueden verse en la documentación de zod/mini

Metadatos y JSON Schema

  • Zod 4 introduce un nuevo sistema para agregar metadatos fuertemente tipados a los schemas
  • Los metadatos no se guardan en el schema mismo, sino en un schema registry que vincula el schema con typed metadata
  • Se puede crear un registro con z.registry(), y el método .register() del schema también permite registrarlo de forma conveniente
  • Zod exporta z.globalRegistry, un registro global que recibe metadatos comunes compatibles con JSON Schema
  • El método .meta() agrega de forma conveniente un schema a z.globalRegistry
  • Por compatibilidad con Zod 3, .describe() sigue disponible, pero en Zod 4 se recomienda .meta()
  • Zod 4 ofrece conversión nativa a JSON Schema mediante z.toJSONSchema()
  • Los metadatos de z.globalRegistry se incluyen automáticamente en la salida de JSON Schema
  • La información para personalizar el JSON Schema generado está en la documentación de JSON Schema

Nuevas expresiones de schemas y funciones de tipos

  • Zod 4 puede inferir correctamente tipos de objetos recursivos
    • Puede expresar tipos recursivos y tipos mutuamente recursivos
    • A diferencia del patrón de tipos recursivos de Zod 3, no requiere type casting
    • El schema resultante es una instancia normal de ZodObject y puede usar todos sus métodos
  • Se añadió un File schema para validar instancias de File
  • z.templateLiteral() representa los tipos template literal de TypeScript
    • Los tipos de schema de Zod que pueden convertirse a string almacenan internamente una expresión regular
    • Entre los objetivos se incluyen strings, formatos de string como z.email(), números, boolean, bigint, enum, literal, undefined/optional, null/nullable y otros template literal
    • El constructor z.templateLiteral los une en una sola super-regex
    • Los formatos de string como z.email() sí se aplican correctamente, pero los refinamientos personalizados no
    • Más detalles en la documentación de template literal
  • Se añadieron nuevos formatos numéricos para representar enteros y tipos de punto flotante de ancho fijo
    • Devuelven instancias de ZodNumber con restricciones inclusive minimum/maximum ya aplicadas
  • También se añadieron formatos numéricos bigint que superan el rango representable de forma segura por number en JavaScript
    • Devuelven instancias de ZodBigInt con restricciones inclusive minimum/maximum ya aplicadas
  • z.literal() ahora puede recibir opcionalmente varios valores

Errores, internacionalización y formatos de string

  • Zod 4 introduce una nueva API de locales para traducir globalmente los mensajes de error a varios idiomas
  • La lista completa de locales compatibles está en Customizing errors y se actualizará conforme se agreguen más idiomas soportados
  • Zod implementa la función de nivel superior z.prettifyError para convertir ZodError en un string con un formato amigable para el usuario
    • Actualmente el formato no puede configurarse
    • Puede cambiar en el futuro
    • Si ya se usa zod-validation-error, se puede seguir usando
  • Todos los formatos de string, como email, fueron promovidos a funciones de nivel superior del módulo z
    • Es más conciso y favorece el tree shaking
    • La API equivalente basada en métodos, como z.string().email(), sigue disponible pero está deprecated
    • Se eliminará en la próxima versión major
  • La API z.email() soporta expresiones regulares personalizadas
    • No existe una sola regex canónica para email, y cada aplicación puede elegir criterios más estrictos o más flexibles
    • Zod exporta algunas regex comunes por conveniencia

Conversión de booleanos y simplificación de la personalización de errores

  • La API existente z.coerce.boolean() convierte valores falsy en false y valores truthy en true
    • false, undefined, null, 0, "", NaN, etc. se convierten en false
    • Este comportamiento es consistente con las demás APIs de z.coerce
  • Zod 4 introduce z.stringbool() para una coerción de booleanos más sofisticada, estilo variables de entorno
  • La mayoría de los cambios incompatibles de Zod 4 están relacionados con la API de personalización de errores
  • La personalización de errores se unificó en un solo parámetro error
    • message es reemplazado por error
    • El parámetro message sigue siendo compatible, pero está deprecated
    • invalid_type_error y required_error se reemplazan por error con sintaxis de función
    • errorMap también se reemplaza por error con sintaxis de función

Composición, refinamiento y transformaciones

  • z.discriminatedUnion() ahora soporta varios tipos de schema que antes no eran compatibles
    • Incluyendo union y pipe
    • Un discriminated union puede usarse como miembro de otro discriminated union, por lo que ahora es componible
  • En Zod 3, los refinamientos se guardaban en una clase ZodEffects que envolvía el schema original
    • Esa estructura hacía incómodo mezclar .refine() con otros métodos de schema como .min()
  • En Zod 4, los refinamientos se guardan dentro del schema, lo que permite usar .refine() junto con otros métodos de forma natural
  • El nuevo método .overwrite() expresa transformaciones que no cambian el tipo inferido
    • .transform() produce un tipo de salida que no puede introspectarse en tiempo de ejecución, y la función de transformación es una caja negra que puede devolver cualquier cosa
    • Por eso no hay forma segura de convertirlo a JSON Schema
    • .overwrite() devuelve una instancia de la clase original
    • La función overwrite se almacena como refinamiento y no modifica el tipo inferido
  • Los métodos existentes .trim(), .toLowerCase() y .toUpperCase() fueron reimplementados usando .overwrite()

Una base para autores de librerías

  • Con la incorporación de Zod Mini, se creó el subpaquete zod/v4/core, que contiene la funcionalidad principal compartida por Zod y Zod Mini
  • zod/v4/core amplía a Zod de una librería simple a una base rápida de validación que puede integrarse dentro de otras librerías
  • Si se quiere crear una librería de schemas, se pueden tomar como referencia las implementaciones de Zod y Zod Mini para construir sobre zod/v4/core
  • Para autores de librerías se ofrece la guía For library authors
    • Cubre las best practices al construir sobre Zod
    • Responde preguntas frecuentes sobre cómo dar soporte simultáneo a Zod 3, Zod 4 y Mini

1 comentarios

 
GN⁺ 2025-05-20
Opiniones de Hacker News
  • Soy el autor, pregúntenme lo que sea. Sobre la política de versiones, dejé bastante detalladas las razones de este enfoque: https://github.com/colinhacks/zod/issues/4371
    En definitiva, npm no está diseñado para manejar bien la situación en la que se encuentra Zod. Decenas o cientos de librerías importan directamente interfaces/clases de Zod y las usan en su API pública, así que cada vez que Zod sube una versión mayor, esas librerías también tienen que sacar una nueva versión mayor
    Visto de forma aislada suena razonable, pero con Zod podía producirse una dolorosa avalancha de versiones para todos, y parecía que una parte importante del ecosistema quedaría fijada en v3 para siempre
    Por eso, de forma similar a Go, optamos por agregar un nuevo subpath en lugar de que el paquete publique una nueva versión con cambios incompatibles. En el ecosistema TypeScript, una librería puede tener una sola peer dependency zod@^3.25.0 e importar lo que necesite desde "zod/v3" y "zod/v4" para admitir ambas versiones al mismo tiempo

    • La mejora de rendimiento de tsc en bases de código grandes es especialmente bienvenida, y los cambios en las uniones discriminadas también parecen ayudar mucho en ciertos escenarios que hasta ahora quedaban cortos
      Entiendo que por circunstancias especiales se haya elegido una política de versiones algo rara, pero desde el punto de vista de un equipo que no tiene que preocuparse por conflictos de versiones de Zod en dependencias transitivas, me gustaría que también existiera un paquete 4.0.0
      Si entendí bien, hay que cambiar los imports a "zod/v4", lo cual es un cambio muy ruidoso, y puede ser molesto tener que detectar con reglas de lint el problema de que el IDE autoimporte desde 'zod'
    • Este enfoque es muy razonable. También significa que las actualizaciones de seguridad de versiones anteriores pueden entregarse dentro del mismo release de la base de código
    • Estoy en móvil, así que no vi si ya está en el artículo, pero me pregunto si arreglar .optional() en TypeScript está incluido entre los 9 o 10 issues principales resueltos: https://github.com/colinhacks/zod/issues/635
      Esto ha sido el mayor dolor con Zod, pero aun así Zod es tan bueno que lo seguimos usando y aguantando
    • Creo que las nuevas funciones me permitirán eliminar muchos hacks temporales que tenía localmente. Para evitar errores tipográficos en nombres de formularios uso mi propia versión de https://github.com/raflymln/zod-key-parser, y me sorprendía que una funcionalidad así no estuviera directamente en la librería
      Me pregunto si consideran que esto queda fuera del alcance de Zod, o si simplemente todavía no habían tenido tiempo de implementarlo. La discusión relacionada está en https://github.com/colinhacks/zod/discussions/2134
    • Si esto significa que la versión más temprana de Zod 4 es 3.25.0, suena un poco absurdo
      He estado usando la versión alfa de Zod durante meses y quería simplemente modificar package.json para actualizar, pero ahora parece que tendré que revisar todo el historial de git
      Agradezco muchísimo el proyecto, pero este feedback en particular parece haberse vuelto innecesariamente difícil. Me pregunto si no podrían haber publicado también 4.x junto con 3.x
  • Que “para simplificar la migración, Zod 4 se distribuya junto con Zod 3 como parte del release zod@3.25 y se importe desde el subpath "/v4"” me parece una señal de que la gestión de dependencias de npm es un completo desastre
    Las peer dependencies están tan rotas que v4 tiene que fingir ser v3

    • Soy el autor. Dejé las razones de este enfoque bastante detalladas aquí: https://github.com/colinhacks/zod/issues/4371
      Es cierto que npm no maneja bien la situación en la que está Zod. Dicho eso, Zod tiene la restricción de no recibir casi ninguna librería. Decenas o cientos de librerías importan interfaces/clases directamente desde "zod" y las usan en sus APIs públicas
      Esas librerías tienen que publicar una nueva versión mayor cada vez que Zod sube una versión mayor, y en Zod eso podría provocar una avalancha de versiones dolorosa para todos. Sinceramente, parecía que una parte importante del ecosistema quedaría fijada en v3 para siempre
      Por eso, de forma parecida a Go, decidimos agregar un nuevo subpath en lugar de publicar una nueva versión del paquete por cada release con incompatibilidades. En el ecosistema TypeScript, con una sola peer dependency zod@^3.25.0 se pueden admitir "zod/v3" y "zod/v4" al mismo tiempo
    • No me parece correcta la conclusión de que “las peer dependencies están rotas y por eso v4 finge ser v3”. Creo que Zod v4 está incluido dentro de v3 para permitir que los usuarios migren gradualmente
      Es decir, refactorizar cada uso uno por uno a import ... from 'zod/v4' y, cuando terminen, subir completamente a v4
    • Se siente como si cualquier comentario negativo recibiera votos positivos. Esta decisión parece más bien una forma práctica de permitir que una librería con muchos cambios incompatibles se migre gradualmente, no tanto una limitación intrínseca de npm en sí
    • Puede que mi perspectiva se haya estrechado por usar solo npm durante años, pero me pregunto cuál sería una mejor forma de hacer una migración iterativa de v3 a v4 sin pasar de golpe a gran escala
    • Esto no es un problema exclusivo de npm. El problema de que una dependencia dependa de una versión antigua a través de otra dependencia transitiva aparece en prácticamente todos los ecosistemas
      De hecho, npm ofrece más vías de escape, porque si hace falta permite ejecutar varias versiones al mismo tiempo o sobrescribir selectivamente partes del grafo de dependencias transitivas
      ¿Qué sistema de gestión de paquetes resuelve este problema? Incluso plataformas “estables” como Maven manejan estos casos publicando versiones bajo un nuevo namespace, como cuando Apache Commons pasó de v2 a v3
  • Hay una pregunta que me intriga desde hace mucho. He oído que Zod podría encajar aquí, pero aun viendo la documentación no tengo muy claro cómo hacerlo
    Supongamos que una API de servidor devuelve tipos más refinados de lo que puede expresar. Por ejemplo, api/:postid/author devuelve un User, pero puede ser un User normal o un User anónimo, así que campos como username o location podrían venir como null. En ese caso, quizá querrías representar el objeto User como una unión discriminada
    Los objetos que vienen de otros endpoints también podrían necesitar conversión de tipos. A veces un User incluye Post[], y si un Post es una publicación de un moderador, podría tener propiedades especiales
    Antes escribía funciones como normalizeUser() y normalizePost(), pero se volvía desordenado muy rápido. Como cada endpoint devolvía subconjuntos distintos de los modelos User/Post, terminé teniendo unas 5 variantes de normalizePost, y era un caos. Me pregunto cómo suele resolverse este problema

    • Creo que bastaría con usar una unión discriminada
      La idea es separar objetos success y failed usando un campo discriminador como status. Si hay muchas propiedades especiales para moderadores, pero no quieres enumerarlas ni verificarlas todas, puedes definir un comportamiento de passthrough
      Aunque varios métodos tengan esquemas distintos, si comparten una parte común puedes crear un esquema de objeto compartido y luego crear objetos que le agreguen campos adicionales. Si hay muchas posibilidades, seguirá siendo desordenado, pero si la situación ya es desordenada, al menos un validador puede validar ese desorden
    • Idealmente debería haber una única fuente de verdad sobre las formas que puede tener User. Eso podría ser una unión discriminada como User y AnonymousUser
      Si no estás usando TypeScript full-stack, por ejemplo con un backend en Python, podrías definir las distintas formas de User como modelos y uniones de Pydantic, y luego generar el esquema OpenAPI/GraphQL y usar generación de código para crear los tipos del cliente TypeScript
    • Habría que conocer mejor el caso de uso para resolverlo, pero si agregas una propiedad discriminadora como "user_type" a todos los tipos dentro de la unión, se vuelve más fácil manejar los casos generales y especiales
      Por ejemplo, si verificas user.user_type === 'authenticated', el sistema de tipos sabe que después de eso puedes usar user.name
    • No ayuda directamente en este caso, pero GraphQL se creó para esto
      Las bibliotecas TypeScript para consultas GraphQL pueden inferir dinámicamente la forma de la respuesta a partir de los campos seleccionados. Si eliges { user { username posts { text } } }, el tipo de respuesta tendrá posts; si solo eliges { user { username } }, la propiedad posts desaparece por completo
    • El servidor debería exponer los tipos. No tiene sentido escribir los tipos a mano en el cliente
      El servidor sabe qué datos envía, así que debería proporcionar esa información al cliente como metadatos. En la práctica, podría ser que un backend en Python use esquemas de Pydantic, genere automáticamente una especificación OpenAPI a partir de ellos y luego el cliente genere los tipos
  • Zod es mucho mejor que las alternativas que he visto, pero a veces el simple hecho de necesitar esta validación explícita se siente como un fracaso de hacia dónde llegó el desarrollo web moderno
    En el desarrollo full-stack es muy frustrante tener que describir la misma forma de varias maneras. Terminas necesitando validación de entradas en JS, Swagger para definir la API, validación de entradas del lado del servidor, un ORM para que encaje con el esquema y definiciones TypeScript separadas para servidor y cliente, lo cual es tedioso

    • Que TypeScript insista en ser un sistema solo de verificación estática/en tiempo de compilación es una herida lamentable para todo el ecosistema. No quiero que TypeScript se convierta en un verificador en runtime, pero sí me gustaría que expusiera datos de tipos útiles para clases, funciones y objetos
      TypeScript se siente como la mejor única fuente de verdad que tenemos, pero en la práctica las herramientas que intentan hacer reflexión terminan redefiniendo cada una su propio modelo y builder. Hay al menos 5 grandes áreas donde la reflexión es central, y cada una tiene varias implementaciones
      reflect-metadata, una antigua herramienta de emisión de tipos de TypeScript, proporciona algo de información de tipos en runtime, pero apunta a una especificación de decoradores y metadatos muy vieja: https://www.npmjs.com/package/reflect-metadata
      Quizá estemos en el inicio de una unificación. El proyecto Standard Schema parece contar con soporte de la mayoría de las bibliotecas de validación principales. Pero extenderlo a definiciones de API u herramientas ORM todavía está en una etapa muy temprana
      https://github.com/standard-schema/standard-schema?tab=readm...
    • En realidad, ese es el punto central de este tipo de herramientas. Defines una sola vez y generas dinámicamente todo lo que está debajo
      Si cambias algo una vez en el esquema de Zod, se propaga por toda la app junto con la verificación de tipos. El esquema de Zod termina siendo la única fuente de verdad
    • Normalmente no hace falta redefinir los datos por todos lados. Hay muchísimas herramientas para convertir hacia Zod o desde Zod
      Si ya tienes un esquema JSON Schema/Swagger, puedes generar Zod a partir de eso. Si usas un ORM de TypeScript, casi seguro existe un generador de Zod
      Sinceramente, Zod está tan extendido que para mí se volvió una definición de esquema unificada de la que pueden depender las demás partes del stack. Como defines los tipos directamente, los desarrolladores realmente los mantienen actualizados. La documentación Swagger de la empresa siempre va por detrás de los cambios
    • Todas las API son experimentales y están en constante cambio y evolución, y la web también
      Mantener el statu quo solo está bien cuando tratas con clientes y empleadores que solo quieren el resultado y no les importa el cómo. En ese contexto, estas capas desafortunadas de complejidad al menos aumentan las horas facturables
    • Sospecho que muchas de las personas que se quejan de que el desarrollo web moderno es complejo también odiarían la propuesta de reemplazar todo esto simplemente con TypeScript y Zod
      Claro, bajo el supuesto de que Zod sea la biblioteca de definición y validación de esquemas TypeScript que eligieron
  • Zod 4 se ve bien, pero incluso con las mejoras más recientes, ArkType sigue siendo varias veces más rápido, por un margen de un solo dígito.
    Para mantener la compatibilidad hacia atrás y la compatibilidad de sintaxis, a veces es difícil hacerlo mucho más rápido que una biblioteca que arranca completamente desde cero. En un proyecto reciente analicé todas estas herramientas y elegí ArkType en parte por eso. También me pareció que la experiencia con TypeScript era mejor.

    • Vi las métricas de velocidad, y me pregunto si alguien puede explicar dónde esa velocidad hace la diferencia.
      Nosotros solo usamos Zod para validación de formularios, así que pienso: “¿por qué importa esto?”. Me pregunto si hay casos en los que la gente valida cosas como mensajes de entrada de API de alto throughput, donde el rendimiento se vuelve más importante.
    • Me da curiosidad por qué eligieron ArkType en vez de TypeBox.
    • Curiosamente, cuando investigué ni siquiera vi esa herramienta. Yo también me estaba fijando especialmente en la experiencia con TypeScript.
      Aun así, no creo que vaya a migrar desde Zod.
    • ArkType es una pesadilla de escribir, Zod es agradable de escribir.
  • Felicitaciones al equipo de Zod por el nuevo lanzamiento. A riesgo de sonar demasiado negativo, me da escalofríos pensar en la cantidad de cambios incompatibles que aparecen en la guía de migración.
    Si tienes un proyecto que depende mucho de Zod, parece una tarea abrumadora que requerirá bastante concentración y tiempo de los desarrolladores. Me identifico especialmente porque he mantenido en el trabajo algunos proyectos de frontend de 4 o 5 años.
    Los proyectos grandes de React suelen depender de muchas bibliotecas, y cuando cada una introduce cambios grandes, más aún si falta documentación, todo se vuelve abrumador muy rápido. Es una de las partes que más detesto de trabajar con JavaScript: hacer que todo encaje y siga funcionando sin problemas se siente como una cuesta arriba interminable.

    • Totalmente de acuerdo. Manejamos varias apps grandes de Next.js y durante el último año tuvimos que pasar por los grandes cambios de caché de Next.js 14 → 15, Next.js pages → app router, React 18 → 19, Eslint 8 → 9 y Tailwind 3 → 4.
      Sinceramente fue una pesadilla, y pensé que ojalá lo hubiéramos hecho en Django. Contra lo que esperaba, la migración de Tailwind 3 → 4 estuvo entre las más dolorosas.
    • Por eso eligieron una distribución dual junto con una edición mini separada. Es más fácil hacer una migración gradual sin tocar el gestor de paquetes.
      Los usuarios a los que no les interesa la edición mini no tienen que preocuparse por esa parte. Pero las ventajas de tree shaking de la edición mini eran tan grandes que estaban impulsando el desarrollo de alternativas, y Zod tenía que aceptarlo o decaer.
    • Simplemente usa un LLM.
  • Como desarrollador full-stack que opera personalmente un SaaS en producción con miles de usuarios, a veces me alegra darme cuenta de cuántos problemas desconozco por completo por haber decidido no crear una SPA ni usar frameworks de frontend en JS.
    Ni siquiera se me había ocurrido que hiciera falta algo como Zod/ArkType; es la primera vez que lo oigo y no tengo ningún uso para eso.
    Me sorprende la cantidad de esfuerzo, complejidad y herramientas que implica crear una SPA. Si decides no crear una SPA, toda una categoría de problemas simplemente deja de existir. En su lugar, uso el navegador como fue diseñado originalmente, con recargas de página completas y desarrollo centrado en el backend, y a veces agrego reactividad con frameworks solo de backend como Laravel Livewire.
    Todo es simple, desde el control de acceso hasta la validación y la gestión de estado. La app es rápida, responsive, moderna, amigable para SEO y está sirviendo a miles de personas en producción.

    • En dos proyectos grandes donde trabajaban más de 5 equipos, usamos Zod y Protobuf para que la evolución de esquemas funcionara bien. Incluso con un frontend liviano, tiene sentido usar algo que valide esquemas en el backend.
      Al final, en algún lugar hay un esquema. Puede estar definido en el sistema de base de datos o en los modelos del ORM. Pero en proyectos grandes, poner el esquema en el sistema de base de datos o en el ORM puede crear problemas muy difíciles, así que usamos Zod y Protobuf. Creo que Protobuf también podría reemplazarse por completo con Zod o algo parecido.
      El escándalo del Post Office británico involucró un sistema de TI llamado Horizon: https://en.wikipedia.org/wiki/British_Post_Office_scandal
      Al leer los detalles, creo que una validación de esquemas como Zod habría contribuido a evitar este escándalo. En el apéndice técnico de los documentos judiciales de la demanda colectiva también se menciona la ausencia de uso de esquemas: https://en.wikipedia.org/wiki/Bates_%26_Others_v_Post_Office...
    • Zod no tiene relación con las SPA y tampoco es una herramienta exclusiva de frontend. ¿No validas entradas en el código?
    • Si cierras los ojos, a veces toda una categoría de problemas deja de existir.
    • Me da curiosidad cómo haces la validación del lado del servidor.
      Por cómo suena, ahora mismo parece que escribes un montón de if defensivos. O peor aún, quizá dependes solo de la validación de formularios del lado del cliente en HTML.
    • Tenemos muchísimos esquemas de Zod solo de backend que usamos como parte de nuestros pipelines de datos. Así que no parece una herramienta que exista únicamente para resolver problemas de SPA.
  • No soy experto, así que lo digo con cautela, pero pensé que JSON Schema podría ser una buena opción porque, al estar basado en esquemas, permite implementar validadores también en lenguajes que no son TypeScript.
    https://ajv.js.org es una de esas bibliotecas de JSON Schema. Me da curiosidad cómo se compara con Zod.

    • Zod no es una herramienta solo para validar JSON. Puede validar objetos que no se pueden representar en JSON sin conversión, por ejemplo fechas o instancias de clases.
      Si quieres, también se puede usar como conversor a JSON. Por ejemplo, puedes escribir un esquema que reciba una cadena, valide que sea una fecha ISO y devuelva un objeto Date.
    • Zod 4 admite de forma nativa la conversión de esquemas de Zod a JSON Schema. Antes también era posible con bibliotecas de terceros.
      La diferencia importante está en el preprocesamiento y refine. En Zod puedes proporcionar callbacks antes de la validación, y eso es muy útil, pero no se puede expresar en JSON. Por ejemplo, convertir MM/DD/YYYY a DD/MM/YYYY antes de validar una fecha resulta útil con más frecuencia de lo que uno pensaría.
    • En esos casos, JSON Schema es una buena opción, y TypeBox es una forma decente de generarlo.
      Para la validación puedes usar AJV o el propio sistema de validación de esquemas de TypeBox. Este último es mucho más rápido, pero solo admite ejecución síncrona; AJV tiene opciones de validación asíncrona, como comprobaciones contra una base de datos.
    • Para validación entre lenguajes, JSON Schema es lo adecuado. Si lo envuelves con OpenAPI, también obtienes buena documentación de API gratis.
  • Me sorprende la reacción negativa en torno a este tema.
    Probé una versión inicial de Zod v4 y me gustó la nueva API, pero me preocupaba mucho cómo sería la ruta de migración. Incluso pensaba sugerir que se publicara con un nombre de paquete completamente nuevo.
    Pero el enfoque del autor es inteligente. Permite que gente como yo pueda adoptar v4 de inmediato sin tener que esperar a que se actualicen todas las dependencias.

    • Es un buen camino. En algo como la validación, no hay forma de soportar una migración de todo o nada.
  • Justo acababa de empezar a incorporar Zod en un proyecto nuevo, y no pudo haber mejor momento que este.
    Por lo que se ve ahora, parece que habría tenido que cambiar muchísimas cosas para pasar a v4.