Communitygithub.com

Schémas Zod

Une bibliothèque d'opinions sur l'utilisation de Zod pour la validation, le parsing et les transformations de données dans une base de code.

Qu'est-ce que Schémas Zod ?

Ce skill définit des règles strictes et complètes pour l'utilisation de Zod 4 dans une base de code. Il agit comme un guide d'architecture, spécifiant comment et où placer les validations (à la frontière des données), comment nommer et organiser les schémas, et comment choisir entre les différentes API de Zod (parsing, transformations, codecs, unions, etc.). Il est particulièrement utile pour les équipes de développement souhaitant maintenir une cohérence et une sécurité dans la gestion des données. Le skill couvre de nombreux sujets : la gestion des versions (Zod 4 uniquement), les conventions de nommage, les formats de données, les unions discriminées, les transformations et les pipes, les codecs pour les sérialisations réversibles, ainsi que les aspects de performance et de sécurité. Il clarifie également ce qui n'est pas du ressort de Zod (par exemple, la sécurité applicative, la mise en cache). Le skill est conçu pour être utilisé avec des agents comme Claude Code, Cursor ou Codex, et se base sur le fichier `SKILL.md` détaillé fourni. Il référence des documents spécialisés pour chaque domaine, et chaque instruction est soit vérifiée contre une version spécifique de Zod, soit marquée comme nécessitant une consultation de la documentation officielle.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add axross/skills

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

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
  • unknown en amont du parse et z.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) de v3.zod.dev (Zod 3) avant de faire confiance à une page
  • choisir entre zod, zod/mini, zod/locales, et les permaliens zod/v4/*
  • le TypeScript 5.5+ et strict: true supposé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 X et zX, et en choisir une par dépôt
  • les primitives partagées EntityId, Timestamp, et NonEmptyString comme vocabulaire dont les autres schémas sont composés
  • .brand<"Name">(), sa direction "out"/"in"/"inout", et les fixtures qu'elle force à passer par un parse
  • 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(), et z.iso.datetime() qui ont remplacé les méthodes z.string().x()
  • choisir le strict z.uuid() plutôt que le permissif z.guid(), et z.httpUrl() plutôt que z.url() pour une URL récupérée
  • z.stringFormat() pour un format propre au projet et z.templateLiteral() pour un type de template literal
  • la plage d'entiers sûrs de z.int(), le rejet de Infinity, et les largeurs fixes z.int32() et z.float64()
  • z.enum() plutôt que l'obsolète z.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, et z.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, et z.partialRecord()
  • z.tuple() là où .nonempty() ne produit plus un type de tuple, plus z.file() et z.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 simple z.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éfaut
  • z.intersection() qui lance une simple Error plutôt qu'une ZodError sur 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 exactOptionalPropertyTypes fait 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'exception
  • ctx.addIssue(), z.NEVER, et le path qui fait atterrir une erreur sur un champ spécifique
  • abort pour arrêter une chaîne, et le when de 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 pas
  • z.input versus z.output/z.infer, et les bugs de formulaire et de fixture dus à leur confusion
  • ctx.issues.push ou le ctx.addIssue de la 4.4 avec z.NEVER pour é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 formes safe* et *Async, plus z.invertCodec()
  • les modèles documentés isoDatetimeToDate, json, stringToURL, et base64ToBytes — 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-ZodError lors 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("") renvoyant 0, et z.coerce.boolean().parse("false") renvoyant true
  • z.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 undefined plus 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 parse retourne, et l'identité de référence qu'elle brise donc
  • remapper ZodError vers 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.issues avec son code et path, et les alias supprimés .errors et .formErrors
  • z.treeifyError(), z.flattenError(), et z.prettifyError(), choisis par le consommateur
  • le paramètre error unifié qui a remplacé message, invalid_type_error, et errorMap
  • la précédence — schéma, par-parse, z.config({ customError }), locale — qui s'est inversée dans Zod 4
  • reportInput plaç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 étendre GlobalMeta par 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, et uri de z.toJSONSchema()
  • io: "input" produisant un document différent de la vue de sortie par défaut
  • les types date, map, set, transform, et bigint sans représentation en Schéma JSON

Sortie Structurée pour Modèle

Voir model-structured-output.md pour :

  • un schéma comme contrat generateObject ou outil, et satisfies z.ZodRawShape là 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.field pour que la sortie du modèle ne puisse pas dériver du type du domaine qu'elle alimente
  • redemander à partir d'une ZodError sous 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.input pour les valeurs du formulaire et les valeurs par défaut, z.output pour le gestionnaire de soumission
  • path sur 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 magasin
  • z.instanceof() pour les types propres d'un pilote et z.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/mini et 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 que z.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

Skills associés