Schéma Zod
Utilisez cette capacité chaque fois qu'une modification touche à Zod — un schéma en cours d'écriture, un appel à parse, un décodage de charge utile, ou une erreur qui remonte. Elle possède la couche schéma : la forme, l'appel parse, le type que cette forme produit, l'erreur qu'elle génère, et le codec qui transporte les données entre un format filaire et un modèle du domaine.
Elle ne possède pas quatre questions voisines, chacune appartenant à une capacité spécifique :
- Si une entrée est non fiable, et doit donc être vérifiée — c'est le jugement d'une capacité de sécurité applicative. Ce skill suppose que ce jugement est rendu et explique comment Zod l'exécute.
- Qu'un point d'ancrage existe pour placer le
parse— un gestionnaire de route, une fonction serveur, une action de formulaire — c'est un fait d'une capacité de framework. - Quand une charge utile récupérée est re-récupérée, mise en cache ou invalidée — c'est le souci d'une capacité de gestion d'état serveur. Ce skill place uniquement un
parseà l'intérieur de la fonction de requête qu'elle possède. - Comment un composant reçoit, affiche et est testé par rapport au résultat parsé — c'est le souci d'une capacité de développement de composants.
Lorsqu'une règle ici a une contrepartie dans l'une de ces capacités, ce skill indique le mécanisme Zod et nomme l'autre comme propriétaire.
Discipline de version. Ce skill est rédigé pour Zod 4 uniquement. Zod 3 est hors de portée en tant que version supportée : pas de chemin de migration, pas de guide zod/v3, et aucune règle énoncée dans sa forme Zod 3. Le seul endroit où Zod 3 apparaît est en tant que signal de détection — une liste d'idiomes obsolètes, afin que le code obsolète puisse être reconnu et remplacé par la forme actuelle. Il s'agit d'une règle Zod 4 concernant une base de code Zod 4, et non d'une couverture de Zod 3. La limite est plus importante que d'habitude ici, car les réponses Zod 3 surpassent encore les réponses Zod 4 dans les tutoriels, les forums et la mémoire du modèle — et la plupart des idiomes Zod 3 compilent encore avec une installation Zod 4, donc « ça tourne » n'est pas une preuve qu'une règle est à jour. Zod 4 évolue également au sein de sa majeure : z.xor, z.invertCodec, et le paramètre de direction .brand sont tous arrivés après 4.0. Chaque instruction sensible à la version indique ici contre quoi elle a été vérifiée, et lorsqu'une surface est connue pour bouger, la règle est une recherche — consultez la documentation de la version installée à https://zod.dev/ — plutôt qu'un nom d'API figé. Traitez toute affirmation non versionnée à propos d'une API Zod, dans ce skill ou ailleurs, comme suspecte.
Vérifié contre [email protected], publié le 2026-05-04 — https://zod.dev/ — avec TypeScript 5.5+ et strict: true comme prérequis indiqués. Chaque fichier de référence porte sa propre ligne « Vérifié contre » avec la page source dont ses règles ont été vérifiées.
Hors de portée. Zod 3 dans toutes ses formes. La branche 4.5.0-canary, dont aucune règle ici n'a été dérivée. Les autres bibliothèques de validation, sauf lorsqu'une frontière est partagée avec l'une d'elles — l'interopérabilité Standard Schema est couverte, les API propres de Valibot ou ArkType ne le sont pas. Les outils de génération de code qui émettent des schémas Zod sont nommés lorsqu'ils modifient ce que vous devez encore écrire à la main, mais leur propre configuration leur appartient.
Les mots-clés « DOIT », « NE DOIT PAS », « OBLIGATOIRE », « DEVRAIT », « NE DEVRAIT PAS », « RECOMMANDÉ », « PEUT », et « OPTIONNEL » dans ce document doivent être interprétés comme décrit dans le RFC 2119.
La Frontière de Validation
Voir validation-boundary.md pour :
- placer l'unique
parseà la frontière où les données entrent, et ne jamais re-parser en aval unknownen amont duparseetz.infer<typeof Schema>en aval, jamais une interface écrite à la main- quelles questions appartiennent à une capacité de sécurité applicative, de framework, d'état serveur ou de composant
- les cas où un schéma coûte sans rien acheter — données internes, valeur déjà parsée, boucle par élément
- exécuter Zod avec un deuxième validateur, et les convertir entre eux à un seul endroit
Version et Paquets
Voir version-and-packages.md pour :
- distinguer
zod.dev(Zod 4) dev3.zod.dev(Zod 3) avant de faire confiance à une page - choisir entre
zod,zod/mini,zod/locales, et les permalienszod/v4/* - le TypeScript 5.5+ et
strict: truesupposés, sans quoi l'optionalité inférée est non fiable - les seuils de version mineure pour
z.xor,z.invertCodec,.safeExtend,z.property, et la direction.brand - les idiomes Zod 3 qui compilent encore avec Zod 4, comme signal d'obsolescence
Modules de Schémas
Voir schema-modules.md pour :
- les conventions de nommage
const X/type XetzX, et en choisir une par dépôt - les primitives partagées
EntityId,Timestamp, etNonEmptyStringcomme vocabulaire dont les autres schémas sont composés .brand<"Name">(), sa direction"out"/"in"/"inout", et les fixtures qu'elle force à passer par unparse- dériver avec
.shape,.extend,.safeExtend,.pick,.omit, et le lancer de.merge()en 4.4 sur les raffinements - placer chaque schéma à la portée du module plutôt que de le reconstruire par requête ou rendu
Primitives et Formats
Voir primitives-and-formats.md pour :
- les méthodes de premier niveau
z.email(),z.url(),z.uuid(), etz.iso.datetime()qui ont remplacé les méthodesz.string().x() - choisir le strict
z.uuid()plutôt que le permissifz.guid(), etz.httpUrl()plutôt quez.url()pour une URL récupérée z.stringFormat()pour un format propre au projet etz.templateLiteral()pour un type de template literal- la plage d'entiers sûrs de
z.int(), le rejet deInfinity, et les largeurs fixesz.int32()etz.float64() z.enum()plutôt que l'obsolètez.nativeEnum(), avec.exclude()et.extract()
Objets et Collections
Voir objects-and-collections.md pour :
z.object()qui supprime les clés non modélisées, etz.strictObject(),z.looseObject(), et.catchall()qui modifient ce comportement- l'auto-référence via un accesseur, et l'annotation de type de retour dont une erreur de circularité a besoin
- les deux arguments requis de
z.record(), les clés d'énumération exhaustives, etz.partialRecord() z.tuple()là où.nonempty()ne produit plus un type de tuple, plusz.file()etz.json()- parser un schéma de tableau une fois plutôt qu'un schéma d'élément par élément
Unions
Voir unions.md pour :
z.discriminatedUnion()pour le rétrécissement, la qualité des erreurs et la vitesse de parsing par rapport à une simplez.union()- le discriminateur littéral que chaque branche doit fixer, et les unions et pipes imbriqués que Zod 4 autorise à l'intérieur
z.xor()pour le cas où une valeur correspondant à deux branches est un défautz.intersection()qui lance une simpleErrorplutôt qu'uneZodErrorsur un résultat non fusionnable- l'union de formes à champs optionnels qui aurait dû être un seul objet
Optionalité et Valeurs par Défaut
Voir optionality-and-defaults.md pour :
- choisir
.optional(),.nullable(), ou.nullish()en fonction de ce que le producteur émet réellement .default()qui court-circuite sur le type de sortie par rapport à.prefault()qui parse sur le type d'entrée.catch()qui transforme un échec de parsing en une valeur de repli, et quand cela cache un producteur dérivant.nullish().transform((v) => v ?? null)pour réduire un producteur mixte null-et-undefini- ce que
exactOptionalPropertyTypesfait au type inféré d'une propriété optionnelle
Raffinements
Voir refinements.md pour :
.refine(),.superRefine(), et.check(), et la règle qu'aucun d'eux ne peut lancer d'exceptionctx.addIssue(),z.NEVER, et lepathqui fait atterrir une erreur sur un champ spécifiqueabortpour arrêter une chaîne, et lewhende la 4.4 pour sauter une vérification dont les entrées sont déjà invalides- un raffinement asynchrone forçant
.parseAsync()sur tous les appelants existants du schéma composé - une règle de permission, de quota ou d'unicité appartenant au domaine plutôt qu'au schéma
Transformations et Pipes
Voir transforms-and-pipes.md pour :
.transform()après la validation,z.preprocess()avant, et.pipe()entre deux schémas.overwrite()là où la valeur change mais que le type et son introspectabilité ne doivent pasz.inputversusz.output/z.infer, et les bugs de formulaire et de fixture dus à leur confusionctx.issues.pushou lectx.addIssuede la 4.4 avecz.NEVERpour échouer depuis l'intérieur d'une transformation- où la remodelation des données du producteur se termine et où commence une décision du domaine
Codecs
Voir codecs.md pour :
z.codec(input, output, { decode, encode })pour une transformation de frontière que.transform()ne peut pas inverser.decode()et.encode()avec leurs formessafe*et*Async, plusz.invertCodec()- les modèles documentés
isoDatetimeToDate,json,stringToURL, etbase64ToBytes— copiés, non importés - les valeurs par défaut et
.catch()s'appliquant uniquement lors du décodage, et une.transform()faisant lancer une exception non-ZodErrorlors de l'encodage - le codec total qui ne peut pas échouer, et la garantie de forme qu'il ne donne donc pas
Coercition et Configuration
Voir coercion-and-config.md pour :
z.coerce.number().parse("")renvoyant0, etz.coerce.boolean().parse("false")renvoyanttruez.stringbool()comme construction qui rejette une valeur qui n'est ni dans l'ensemble truthy ni dans l'ensemble falsy- les chaînes de requête, les données de formulaire et les variables d'environnement comme les trois sources à valeurs de type chaîne
- parser la configuration une fois au démarrage et terminer plutôt que de retourner
undefinedplus tard - garder la configuration secrète hors des logs et hors du bundle client
Parsing
Voir parsing.md pour :
.parse()quand un échec est un défaut,.safeParse()quand c'est un résultat sur lequel bifurquer.parseAsync()étant obligatoire plutôt qu'optionnel dès qu'une vérification dans le schéma est asynchrone- la copie profonde qu'un
parseretourne, et l'identité de référence qu'elle brise donc - remapper
ZodErrorvers une erreur du domaine pour que Zod reste hors des signatures du domaine - logger la frontière et les chemins des problèmes, jamais l'entrée qui a échoué
Erreurs
Voir errors.md pour :
error.issuesavec soncodeetpath, et les alias supprimés.errorset.formErrorsz.treeifyError(),z.flattenError(), etz.prettifyError(), choisis par le consommateur- le paramètre
errorunifié qui a remplacémessage,invalid_type_error, eterrorMap - la précédence — schéma, par-parse,
z.config({ customError }), locale — qui s'est inversée dans Zod 4 reportInputplaçant une entrée non fiable dans une erreur qui voyage vers un tracker ou un client
Métadonnées et Schéma JSON
Voir metadata-and-json-schema.md pour :
.meta(),z.registry(),z.globalRegistry, et étendreGlobalMetapar fusion de déclaration- les métadonnées liées à une instance de schéma, donc
.optional()ou.extend()les orphelinent - les options
target,io,unrepresentable,cycles,reused, eturidez.toJSONSchema() io: "input"produisant un document différent de la vue de sortie par défaut- les types
date,map,set,transform, etbigintsans représentation en Schéma JSON
Sortie Structurée pour Modèle
Voir model-structured-output.md pour :
- un schéma comme contrat
generateObjectou outil, etsatisfies z.ZodRawShapelà où une forme brute est souhaitée - le texte
.describe()atteignant le modèle comme instruction plutôt que comme documentation .nullable()survivant au mode strict d'un fournisseur là où.optional()et.nullish()sont rejetés- réutiliser
.shape.fieldpour que la sortie du modèle ne puisse pas dériver du type du domaine qu'elle alimente - redemander à partir d'une
ZodErrorsous une tentative limitée, plutôt que de corriger une sortie invalide
Formulaires
Voir forms.md pour :
- un résolveur spécifique à Zod pour les détails de problème de Zod, ou un résolveur Standard Schema pour l'indépendance de la bibliothèque
z.inputpour les valeurs du formulaire et les valeurs par défaut,z.outputpour le gestionnaire de soumissionpathsur un raffinement inter-champs comme seul moyen pour une erreur d'atteindre le bon champ d'entrée- la chaîne vide qu'un champ numérique vide soumet, et la clé absente qu'une case à cocher non cochée envoie
- la re-parser côté serveur qu'un schéma côté client ne remplace jamais
Frontières de Magasin de Données
Voir data-store-boundaries.md pour :
- la forme stockée et le modèle du domaine comme deux schémas avec une transformation entre eux
- les moitiés de lecture et d'écriture écrites comme une paire, afin qu'un champ renommé ne puisse pas dériver entre elles
.partial()pour un correctif et.omit().extend()pour une entrée de création transportant des sentinelles de magasinz.instanceof()pour les types propres d'un pilote etz.property()pour contraindre l'un de leurs champs- une charge utile variant selon la profondeur de la requête, l'état du brouillon ou la locale — et le schéma tout-optionnel qui n'est pas la réponse
Performance et Empreinte
Voir performance-and-footprint.md pour :
- les gains de parsing publiés d'environ 14x, 7x et 6,5x, et la baisse d'instanciation de types d'environ 25 000 à 175
- l'API fonctionnelle de
zod/miniet son noyau de 1,88 Ko, et pourquoi un serveur ne devrait pas l'adopter - la construction de schéma déplacée hors d'un chemin chaud, et une collection parsée une fois plutôt que par élément
.check()plutôt que.refine()et une union discriminée plutôt qu'une union linéaire, sur un chemin mesuréz.looseObject()sautant la passe de suppression de clés, et la protection à laquelle on renonce
Posture de Sécurité
Voir security-posture.md pour :
- le stripping de
z.object()comme protection contre l'assignation de masse, et ce quez.looseObject()réadmet - un parsing réussi n'étant ni un échappement HTML, ni une paramétrisation SQL, ni une garantie de récupération sécurisée
.max()placé avant une.regex()ou un raffinement coûteux, pour limiter le travail contrôlé par un attaquant- les tableaux non bornés, la profondeur de récursion non bornée, et les entrées cycliques qui bouclent indéfiniment
- un schéma de réponse basé sur une liste blanche, sans quoi un champ privé part avec la charge utile
Test des Schémas
Voir testing-schemas.md pour :
- pourquoi affirmer que
z.email()rejette"nope"teste Zod plutôt que le schéma z.input<typeof Schema>comme type de fixture, construit à partir d'une charge utile observée réelle