본문으로 건너뛰기

라이브러리 작성자용

이 페이지는 주로 Zod 기반 도구를 만드는 라이브러리 작성자를 위한 문서입니다.

라이브러리 작성자에게 필요한 지침이 이 페이지에 빠져 있다고 생각한다면 이슈를 열어 주세요!

Zod에 의존해야 하나요?

먼저 Zod에 반드시 의존해야 하는지 확인하세요.

사용자가 정의한 스키마를 받아 블랙박스 방식으로 검증하는 라이브러리를 만든다면 Zod와 직접 통합할 필요가 없을 수도 있습니다. 대신 Standard Schema를 살펴보세요. Zod를 비롯해 TypeScript 생태계의 주요 검증 라이브러리가 구현하는 공통 인터페이스입니다(전체 목록 참조).

이 사양은 사용자 정의 스키마를 받아 "블랙박스" 검증기처럼 다룰 때 매우 유용합니다. 사양을 준수하는 라이브러리라면 무엇이든 추론된 입력/출력 타입을 추출하고 입력을 검증한 뒤 표준화된 오류를 받을 수 있습니다.

Zod의 특정 기능이 필요하다면 계속 읽어보세요.

피어 의존성을 어떻게 구성하나요?

Zod를 기반으로 구축한 모든 라이브러리는 "zod""peerDependencies"에 포함해야 합니다. 그러면 사용자가 프로젝트에 설치한 Zod를 그대로 사용할 수 있습니다.

// package.json
{
// ...
"peerDependencies": {
"zod": "^4.0.0"
}
}

개발 중에는 자체 피어 의존성 요구 사항을 충족해야 하므로 "zod""devDependencies"에도 추가하세요.

// package.json
{
"peerDependencies": {
"zod": "^4.0.0"
},
"devDependencies": {
"zod": "^4.0.0"
}
}

기존 라이브러리를 확장하면서 Zod 3 사용자를 계속 지원하려면 Zod 4와 함께 Zod 3을 지원하려면?에서 더 넓은 피어 의존성 범위를 확인하세요.

어떤 하위 경로에서 가져와야 하나요?

"zod/v4/core" 하위 경로에서 Zod 4 코어 패키지를 가져옵니다.

import * as z4 from "zod/v4/core";

이 하위 경로를 Zod 4의 "영구 링크"라고 생각하면 됩니다. 향후 zod 패키지의 메이저 버전이 바뀌어도 계속 사용할 수 있습니다. 다른 영구 링크 하위 경로는 "zod/v3"뿐이며, Zod 3도 함께 지원할 때만 필요합니다.

일반적으로 다른 경로에서 가져오면 안 됩니다. Zod Core는 Zod 4 Classic과 Zod 4 Mini를 모두 뒷받침하는 공통 라이브러리입니다. 둘 중 하나에만 특화된 기능을 구현하는 것도 바람직하지 않습니다. 다음 하위 경로에서 가져오지 마세요.

  • "zod" — ❌ 3.x 릴리스에서는 Zod 3을, 4.x 릴리스에서는 Zod 4를 내보냅니다. 대신 영구 링크를 사용하세요.
  • "zod/v4""zod/v4/mini" — ❌ 이 하위 경로는 각각 Zod 4 Classic과 Mini를 제공합니다. 라이브러리가 Zod와 Zod Mini에서 모두 작동하게 하려면 "zod/v4/core"에 정의된 기본 클래스를 기준으로 구현해야 합니다. "zod/v4" 모듈의 클래스를 참조하면 라이브러리가 Zod Mini에서 작동하지 않으며, 그 반대도 마찬가지입니다. 이 방식은 강력히 권장하지 않습니다. 대신 "zod/v4/core"를 사용하세요. 이 패키지는 Zod Classic과 Zod Mini가 확장하는 $ 접두사 하위 클래스를 내보냅니다. Classic과 Mini 하위 클래스의 내부 구조는 동일하며, 구현하는 도우미 메서드만 다릅니다.

이 버전 관리 방식에 관한 전체 맥락은 Zod 4의 버전 관리 글을 참고하세요.

Zod 4와 함께 Zod 3을 지원하려면?

기존 Zod 3 사용자가 있는 라이브러리를 유지 관리한다면 이들을 포기하지 않고 Zod 4까지 지원하도록 확장할 수 있습니다. 피어 의존성 범위를 두 버전에 걸치도록 넓히세요. "zod/v4" 하위 경로는 3.25.0부터 제공됩니다.

// package.json
{
// ...
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
}
}

이 작업에 라이브러리의 새 메이저 버전이 필요한 것은 아닙니다. 피어 의존성을 올리려면 사용자가 npm upgrade zod를 실행해야 하지만, zod@3.24zod@3.25 사이에는 호환성을 깨는 변경은커녕 코드 변경 자체가 없었습니다. 따라서 Zod 4 지원은 마이너 릴리스에 포함할 수 있습니다. 어차피 메이저 릴리스를 준비 중이라면 Zod 3 지원을 제거하고 피어 범위를 ^4.0.0으로 좁히는 편이 더 깔끔합니다.

v3.25.0부터 zod 패키지는 각 하위 경로에 Zod 3과 Zod 4를 모두 포함하므로 두 버전을 나란히 가져올 수 있습니다.

import * as z3 from "zod/v3";
import * as z4 from "zod/v4/core";

type Schema = z3.ZodTypeAny | z4.$ZodType;

function acceptUserSchema(schema: z3.ZodTypeAny | z4.$ZodType) {
// ...
}

런타임 시 Zod 3 스키마와 Zod 4 스키마를 구별하려면 "_zod" 속성을 확인하세요. 이 속성은 Zod 4 스키마에만 정의됩니다.

import type * as z3 from "zod/v3";
import type * as z4 from "zod/v4/core";

declare const schema: z3.ZodTypeAny | z4.$ZodType;

if ("_zod" in schema) {
schema._zod.def; // Zod 4 schema
} else {
schema._def; // Zod 3 schema
}

Zod와 Zod Mini를 동시에 지원하려면?

라이브러리 코드는 "zod/v4/core"에서만 가져와야 합니다. 이 하위 패키지는 Zod와 Zod Mini 간에 공유되는 인터페이스, 클래스 및 유틸리티를 정의합니다. 이 규칙을 따르는 한 Zod와 Zod Mini는 모두 자동으로 작동합니다.

// library code
import * as z4 from "zod/v4/core";

export function acceptObjectSchema<T extends z4.$ZodObject>(schema: T){
// parse data
z4.parse(schema, { /* somedata */});
// inspect internals
schema._zod.def.shape;
}

공유 기본 인터페이스를 기반으로 구축하면 두 하위 패키지를 동시에 안정적으로 지원할 수 있습니다. 이 함수는 Zod와 Zod Mini 스키마를 모두 받을 수 있습니다.

// user code
import { acceptObjectSchema } from "your-library";

// Zod 4
import * as z from "zod";
acceptObjectSchema(z.object({ name: z.string() }));

// Zod 4 Mini
import * as zm from "zod/mini";
acceptObjectSchema(zm.object({ name: zm.string() }))

코어 하위 라이브러리의 구성은 Zod Core 페이지에서 자세히 알아볼 수 있습니다.

사용자 정의 스키마를 받으려면?

사용자 정의 스키마를 받는 것은 Zod 기반 라이브러리의 기본 작업입니다. 이 섹션에서는 이를 위한 모범 사례를 설명합니다.

처음에는 다음과 같이 Zod 스키마를 받는 함수를 작성하고 싶을 수 있습니다.

import * as z4 from "zod/v4/core";

function inferSchema<T>(schema: z4.$ZodType<T>) {
return schema;
}

이 접근 방식은 올바르지 않으며 TypeScript가 인수 타입을 정확하게 추론하는 것을 방해합니다. 무엇을 전달하든 schema 타입은 $ZodType의 인스턴스가 됩니다.

inferSchema(z.string());
// => $ZodType<string>

이 접근 방식에서는 타입 정보, 즉 입력이 실제로 _어느 하위 클래스_인지(이 경우 ZodString)에 관한 정보가 사라집니다. 따라서 .min() 같은 문자열 전용 메서드를 inferSchema의 결과에서 호출할 수 없습니다. 대신 제네릭 매개변수가 Core Zod 스키마 인터페이스를 확장해야 합니다.

function inferSchema<T extends z4.$ZodType>(schema: T) {
return schema;
}

inferSchema(z.string());
// => ZodString ✅

입력 스키마를 특정 하위 클래스로 제한하려면 다음과 같이 작성합니다.


import * as z4 from "zod/v4/core";

// only accepts object schemas
function inferSchema<T extends z4.$ZodObject>(schema: T) {
return schema;
}

입력 스키마에서 추론되는 출력 타입을 제한하려면 다음과 같이 작성합니다.


import * as z4 from "zod/v4/core";

// only accepts string schemas
function inferSchema<T extends z4.$ZodType<string>>(schema: T) {
return schema;
}

inferSchema(z.string()); // ✅

inferSchema(z.number());
// ❌ The types of '_zod.output' are incompatible between these types.
// // Type 'number' is not assignable to type 'string'

스키마로 데이터를 파싱하려면 최상위 z4.parse/z4.safeParse/z4.parseAsync/z4.safeParseAsync 함수를 사용하세요. z4.$ZodType 하위 클래스에는 메서드가 없습니다. 일반적인 파싱 메서드는 Zod와 Zod Mini에 구현되어 있지만 Zod Core에서는 사용할 수 없습니다.

function parseData<T extends z4.$ZodType>(data: unknown, schema: T): z4.output<T> {
return z.parse(schema, data);
}

parseData("sup", z.string());
// => string