Communitygithub.com

axross/skills

Zod 스키마 레이어를 위한 세분화된 기술 및 모범 사례 모음 — 검증, 변환, 코덱, 에러 처리 및 보안 경계를 포함합니다.

skills란 무엇인가요?

이 스킬은 Zod 4를 사용하는 코드베이스에서 스키마 레이어를 담당하는 AI 에이전트를 위한 포괄적인 가이드입니다. Zod 4의 최신 API와 모범 사례를 중심으로 검증 경계(validation boundary), 스키마 모듈 설계, 기본 타입 및 포맷, 객체/컬렉션, 유니온, 선택적 속성, 리파인먼트(refinements), 트랜스폼(transforms), 파이프(pipes), 코덱(codecs), 강제 변환(coercion), 파싱 전략, 에러 처리, 메타데이터, JSON 스키마, 모델 구조화된 출력, 폼, 데이터 저장소 경계, 성능, 보안, 테스트 등 20개 이상의 세부 영역을 다룹니다. 각 주제는 별도의 참조 파일로 구성되어 있으며, Zod 3와의 차이점을 명확히 구분하고 버전별 요구 사항을 명시합니다. TypeScript 5.5+ 및 `strict: true` 설정을 전제로 하며, 실무에서 바로 적용 가능한 구체적인 규칙과 패턴을 제공하여 AI 에이전트가 Zod 관련 코드를 정확하고 일관되게 작성할 수 있도록 돕습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add axross/skills

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Zod 스키마

이 능력은 Zod와 관련된 변경 사항(스키마 작성, 파싱 배치, 페이로드 디코딩, 에러 표시)이 있을 때마다 사용합니다. 이 능력은 스키마 레이어를 담당합니다: 형태, 파싱 호출, 해당 형태가 생성하는 타입, 생성되는 에러, 그리고 와이어 형식과 도메인 모델 간에 데이터를 전달하는 코덱.

다음 4가지 인접 질문은 각각 다른 능력이 담당하므로 이 능력의 범위가 아닙니다:

  • 입력이 전혀 신뢰할 수 없는지 여부와 따라서 반드시 검사해야 하는지 — 애플리케이션 보안 능력의 판단입니다. 이 스킬은 해당 판단이 이미 내려졌다고 가정하고 Zod가 이를 어떻게 수행하는지 설명합니다.
  • 파싱이 위치할 훅의 존재 여부 — 라우트 핸들러, 서버 함수, 폼 액션 — 프레임워크 능력의 사실입니다.
  • 가져온 페이로드를 다시 가져오거나, 캐시하거나, 무효화할 시점 — 서버 상태 능력의 관심사입니다. 이 스킬은 자신이 담당하는 쿼리 함수 내에만 파싱을 배치합니다.
  • 구문 분석된 결과를 컴포넌트가 어떻게 수신, 렌더링, 테스트하는지 — 컴포넌트 개발 능력의 관심사입니다.

여기 있는 규칙이 위 능력 중 하나와 대응되는 경우, 이 스킬은 Zod 메커니즘을 명시하고 다른 능력을 소유자로 지명합니다.

버전 규율. 이 스킬은 Zod 4 전용으로 작성되었습니다. Zod 3은 지원 대상에서 제외됩니다: 마이그레이션 경로, zod/v3 가이드라인, 또는 Zod 3 형태의 규칙이 없습니다. Zod 3이 등장하는 유일한 곳은 감지 신호로, 구식 관용구 목록을 제공하여 낡은 코드를 인식하고 현재 형태로 대체할 수 있도록 합니다. 이는 Zod 4 코드베이스에 대한 Zod 4 규칙이지, Zod 3을 다루는 것이 아닙니다. 여기서 경계가 평소보다 더 중요한 이유는, 튜토리얼, 포럼 게시물, 모델 회상 전반에 걸쳐 Zod 3 답변이 여전히 Zod 4 답변보다 우세하고, 대부분의 Zod 3 관용구가 Zod 4 설치 환경에서도 여전히 컴파일되기 때문에 "실행된다"는 사실이 규칙이 최신이라는 증거가 될 수 없기 때문입니다. 또한 Zod 4는 메이저 버전 내에서도 변경됩니다: z.xor, z.invertCodec, .brand 방향 매개변수는 4.0 이후에 추가되었습니다. 모든 버전에 민감한 설명은 검증된 대상을 명시하며, 표면이 변경될 것으로 알려진 곳의 규칙은 조회(lookup) 방식 — 설치된 버전의 공식 문서 https://zod.dev/ 참조 — 이지 고정된 API 이름이 아닙니다. 이 스킬이나 다른 곳에서 Zod API에 대한 버전이 명시되지 않은 주장은 신뢰할 수 없는 것으로 간주하십시오.

검증 기준 [email protected], 2026-05-04 게시 — https://zod.dev/ — TypeScript 5.5+ 및 strict: true 전제 조건과 함께. 각 참조 파일에는 규칙이 검증된 업스트림 페이지와 함께 자체 검증 기준 줄이 있습니다.

범위 밖. 모든 형태의 Zod 3. 4.5.0-canary 라인, 이에 대해 파생된 규칙이 없음. 다른 검증 라이브러리(단, 경계가 공유되는 경우는 제외 — Standard Schema 상호 운용성은 다루지만 Valibot 또는 ArkType의 자체 API는 다루지 않음). Zod 스키마를 생성하는 코드 생성 도구는 수동으로 작성해야 하는 부분이 무엇인지 명시할 때 언급되지만, 해당 도구의 자체 구성은 해당 도구의 책임입니다.

이 문서에서 핵심 단어 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 및 "OPTIONAL"은 RFC 2119에 설명된 대로 해석되어야 합니다.

검증 경계

validation-boundary.md에서 다음 내용을 확인하세요:

  • 데이터가 진입하는 경계에 하나의 파싱을 배치하고, 내부에서 다시 파싱하지 않음
  • 파싱 이전에는 unknown, 이후에는 z.infer<typeof Schema>이며, 수동 인터페이스는 사용하지 않음
  • 애플리케이션 보안, 프레임워크, 서버 상태, 또는 컴포넌트 능력에 속하는 질문들
  • 스키마가 비용 대비 효과를 보지 못하는 경우 — 내부 데이터, 이미 파싱된 값, 항목별 루프
  • Zod를 다른 검증기와 함께 사용하고, 한 곳에서 변환

버전 및 패키지

version-and-packages.md에서 다음 내용을 확인하세요:

  • 페이지를 신뢰하기 전에 zod.dev(Zod 4)와 v3.zod.dev(Zod 3) 구분하기
  • zod, zod/mini, zod/locales, zod/v4/* 고정 링크 중에서 선택하기
  • 가정된 TypeScript 5.5+ 및 strict: true, 이것 없이는 추론된 선택성이 불건전함
  • z.xor, z.invertCodec, .safeExtend, z.property, .brand 방향에 대한 마이너 버전 최소 요구 사항
  • Zod 4에서 여전히 컴파일되는 Zod 3 관용구 (노후화 신호)

스키마 모듈

schema-modules.md에서 다음 내용을 확인하세요:

  • const X / type X 및 zX 명명 규칙, 그리고 저장소당 하나 선택하기
  • 다른 스키마가 구성하는 어휘로서의 공유 EntityId, Timestamp, NonEmptyString 프리미티브
  • .brand<"Name">(), "out"/"in"/"inout" 방향, 그리고 파싱을 강제하는 픽스처
  • .shape, .extend, .safeExtend, .pick, .omit, .merge() (4.4에서 리파인먼트 시 throw)를 사용한 파생
  • 모든 스키마를 요청 또는 렌더링마다 재구축하지 않고 모듈 범위로 호이스팅

프리미티브 및 포맷

primitives-and-formats.md에서 다음 내용을 확인하세요:

  • z.string().x() 메서드를 대체한 최상위 z.email(), z.url(), z.uuid(), z.iso.datetime()
  • 관대한 z.guid() 대신 엄격한 z.uuid() 선택, 가져온 URL에는 z.url() 대신 z.httpUrl() 선택
  • 프로젝트 자체 포맷을 위한 z.stringFormat() 및 템플릿 리터럴 타입을 위한 z.templateLiteral()
  • z.int()의 안전한 정수 범위, Infinity 거부, 고정 너비 z.int32() 및 z.float64()
  • 비권장 z.nativeEnum() 대신 z.enum(), .exclude() 및 .extract()와 함께 사용

객체 및 컬렉션

objects-and-collections.md에서 다음 내용을 확인하세요:

  • z.object()가 모델링되지 않은 키를 제거하며, z.strictObject(), z.looseObject(), .catchall()이 이를 변경함
  • getter를 통한 자기 참조, 순환 오류에 필요한 반환 타입 어노테이션
  • 두 개의 필수 인수를 가진 z.record(), 열거형 키 전체, z.partialRecord()
  • .nonempty()가 더 이상 튜플 타입을 생성하지 않는 z.tuple(), z.file() 및 z.json()
  • 요소별 스키마 대신 배열 스키마를 한 번만 파싱

유니온

unions.md에서 다음 내용을 확인하세요:

  • 단순 z.union()보다 범위 축소, 에러 품질, 파싱 속도 측면에서 우수한 z.discriminatedUnion()
  • 모든 브랜치가 고정해야 하는 리터럴 판별자, Zod 4가 내부에서 허용하는 중첩 유니온 및 파이프
  • 두 브랜치에 모두 일치하는 값이 결함인 경우를 위한 z.xor()
  • 병합 불가능한 결과에 ZodError 대신 일반 Error를 throw하는 z.intersection()
  • 하나의 객체여야 했던 선택적 필드 형태의 유니온

선택성 및 기본값

optionality-and-defaults.md에서 다음 내용을 확인하세요:

  • 생산자가 실제로 내보내는 것에 따라 .optional(), .nullable(), .nullish() 선택
  • 출력 타입에서 단락(short-circuit)되는 .default()와 입력 타입에서 파싱하는 .prefault()
  • 파싱 실패를 대체값으로 전환하는 .catch(), 그리고 이것이 언제 표류하는 생산자를 숨기는지
  • 혼합된 null 및 undefined 생산자를 축소하기 위한 .nullish().transform((v) => v ?? null)
  • exactOptionalPropertyTypes가 선택적 속성의 추론된 타입에 미치는 영향

리파인먼트

refinements.md에서 다음 내용을 확인하세요:

  • .refine(), .superRefine(), .check(), 그리고 이들 중 어느 것도 throw 해서는 안 된다는 규칙
  • ctx.addIssue(), z.NEVER, 특정 필드에 오류를 전달하는 path
  • 체인을 중단하는 abort, 이미 유효하지 않은 입력에 대한 검사를 건너뛰는 4.4의 when
  • 구성된 스키마의 모든 기존 호출자에게 .parseAsync()를 강제하는 비동기 리파인먼트
  • 스키마가 아닌 도메인에 속하는 권한, 할당량, 또는 고유성 규칙

트랜스폼 및 파이프

transforms-and-pipes.md에서 다음 내용을 확인하세요:

  • 검증 후 .transform(), 검증 전 z.preprocess(), 두 스키마 사이의 .pipe()
  • 값은 변경되지만 타입과 그 내부 검사 가능성은 변경되지 않아야 하는 .overwrite()
  • z.input 대 z.output/z.infer, 그리고 이들을 혼동하여 발생하는 형태 및 픽스처 버그
  • ctx.issues.push 또는 z.NEVER와 함께 4.4의 ctx.addIssue를 사용하여 트랜스폼 내부에서 실패 처리
  • 생산자 데이터를 재구성하는 것이 끝나고 도메인 결정이 시작되는 지점

코덱

codecs.md에서 다음 내용을 확인하세요:

  • .transform()이 역전할 수 없는 경계를 위한 z.codec(input, output, { decode, encode })
  • safe* 및 *Async 형태의 .decode()와 .encode(), z.invertCodec()
  • 문서화된 isoDatetimeToDate, json, stringToURL, base64ToBytes 템플릿 — 복사하여 사용, 가져오지 않음
  • 디코드에만 적용되는 기본값 및 .catch(), 인코드 시 비-ZodError를 throw하는 .transform()
  • 실패할 수 없는 전체 코덱, 따라서 제공하지 않는 형태 보장

강제 변환 및 구성

coercion-and-config.md에서 다음 내용을 확인하세요:

  • z.coerce.number().parse("")가 0을 반환하고, z.coerce.boolean().parse("false")가 true를 반환함
  • 참(true) 집합에도 거짓(false) 집합에도 속하지 않는 값을 거부하는 구조 z.stringbool()
  • 쿼리 문자열, 폼 데이터, 환경 변수 — 세 가지 문자열 값 소스
  • 시작 시 한 번만 구성을 파싱하고, 나중에 undefined를 노출하는 대신 종료
  • 비밀 구성을 로그 및 클라이언트 번들에서 제외

파싱

parsing.md에서 다음 내용을 확인하세요:

  • 실패가 결함인 경우 .parse(), 분기할 결과인 경우 .safeParse()
  • 스키마의 어떤 검사가 비동기이면 선택 사항이 아닌 필수 사항인 .parseAsync()
  • 파싱이 반환하는 깊은 복사, 이로 인해 깨지는 참조 동일성
  • Zod가 도메인 시그니처에 남지 않도록 ZodError를 도메인 오류로 재매핑
  • 경계와 이슈 경로를 로깅하고, 실패한 입력은 절대 로깅하지 않음

에러

errors.md에서 다음 내용을 확인하세요:

  • code 및 path를 포함하는 error.issues, 제거된 .errors 및 .formErrors 별칭
  • 소비자가 선택하는 z.treeifyError(), z.flattenError(), z.prettifyError()
  • message, invalid_type_error, errorMap을 대체한 통합 error 매개변수
  • Zod 4에서 역전된 우선순위 — 스키마, 파싱별, z.config({ customError }), 로케일
  • 신뢰할 수 없는 입력을 추적기나 클라이언트로 전달하는 오류에 넣는 reportInput

메타데이터 및 JSON 스키마

metadata-and-json-schema.md에서 다음 내용을 확인하세요:

  • .meta(), z.registry(), z.globalRegistry, 선언 병합을 통한 GlobalMeta 확장
  • 스키마 인스턴스에 바인딩되는 메타데이터, 따라서 .optional() 또는 .extend()가 이를 고아로 만듦
  • z.toJSONSchema()의 target, io, unrepresentable, cycles, reused, uri 옵션
  • 기본 출력 뷰와 다른 문서를 생성하는 io: "input"
  • JSON 스키마 표현이 없는 date, map, set, transform, bigint 타입

모델 구조화된 출력

model-structured-output.md에서 다음 내용을 확인하세요:

  • generateObject 또는 도구 계약으로서의 스키마, 원시 형태가 필요할 때 satisfies z.ZodRawShape
  • 모델에 문서가 아닌 명령으로 도달하는 .describe() 텍스트
  • .optional() 및 .nullish()가 거부되는 공급자의 엄격 모드에서 살아남는 .nullable()
  • 모델 출력이 공급하는 도메인 타입에서 벗어나지 않도록 .shape.field 재사용
  • 잘못된 출력을 패치하는 대신 제한된 재시도 하에 ZodError로부터 다시 프롬프트

폼

forms.md에서 다음 내용을 확인하세요:

  • Zod 고유의 이슈 상세 정보를 위한 Zod 특정 리졸버, 또는 라이브러리 독립성을 위한 Standard Schema 리졸버
  • 폼의 값 및 기본값을 위한 z.input, 제출 핸들러를 위한 z.output
  • 오류가 올바른 입력에 도달하는 유일한 방법인 교차 필드 리파인먼트의 path
  • 빈 숫자 필드가 제출하는 빈 문자열, 체크되지 않은 체크박스가 보내는 누락된 키
  • 클라이언트 측 스키마가 절대 대체하지 못하는 서버 측 재파싱

데이터 저장소 경계

data-store-boundaries.md에서 다음 내용을 확인하세요:

  • 저장된 형태와 도메인 모델, 이 둘 사이에 트랜스폼이 있는 두 개의 스키마
  • 읽기 및 쓰기 절반을 하나의 쌍으로 작성하여 이름이 변경된 필드가 둘 사이에서 표류하지 않도록 함
  • 패치를 위한 .partial(), 저장소 센티넬을 전달하는 생성 입력을 위한 .omit().extend()
  • 드라이버의 자체 타입을 위한 z.instanceof(), 해당 필드 중 하나를 제한하는 z.property()
  • 쿼리 깊이, 초안 상태, 로케일에 따라 달라지는 페이로드 — 그리고 답이 아닌 모든 선택적 스키마

성능 및 설치 공간

performance-and-footprint.md에서 다음 내용을 확인하세요:

  • 게시된 약 14배, 7배, 6.5배 파싱 성능 향상, 약 25,000에서 약 175로의 타입 인스턴스화 감소
  • zod/mini의 함수형 API 및 1.88 kB 코어, 그리고 서버가 이를 채택해서는 안 되는 이유
  • 핫 경로 밖으로 호이스팅된 스키마 구성, 항목별이 아닌 한 번에 파싱된 컬렉션
  • 측정된 경로에서 .refine()보다 .check(), 선형 유니온보다 판별 유니온
  • 키 제거 패스를 건너뛰는 z.looseObject(), 그리고 이로 인해 희생되는 보호

보안 태세

security-posture.md에서 다음 내용을 확인하세요:

  • 대량 할당 보호로서의 z.object()의 키 제거, 그리고 z.looseObject()가 다시 허용하는 것
  • 통과하는 파싱이 HTML 이스케이핑, SQL 매개변수화, 또는 안전한 가져오기 보장이 아님
  • 공격자가 제어하는 작업을 제한하기 위해 .regex() 또는 값비싼 리파인먼트 앞에 배치된 .max()
  • 무제한 배열, 무제한 재귀 깊이, 영원히 루프되는 순환 입력
  • 허용 목록 응답 스키마, 없으면 페이로드와 함께 개인 필드가 유출됨

스키마 테스트

testing-schemas.md에서 다음 내용을 확인하세요:

  • z.email()이 "nope"를 거부하는지 단언하는 것이 Zod 자체를 테스트하는 것이지 스키마를 테스트하는 것이 아닌 이유
  • z.input<typeof Schema>를 픽스처 타입으로 사용, 관찰된 페이로드로부터 구축

…

[번역을 위해 잘림]

관련 스킬