자물쇠 모양 장치가 값이 적힌 막대를 걸러 이름표 카드로 전달하는 비밀 바인딩 분리 이미지

cloudflare workers types secrets.required: .env 없이 바인딩 타입 생성 검증하기

cloudflare workers types secrets.required는 secret 값을 타입 생성기에 건네는 기능이 아니다. Worker가 요구하는 이름을 Wrangler 설정에 선언해, .dev.vars.env가 없는 CI에서도 같은 Env 타입을 만들기 위한 기능이다. 로컬 파일의 키를 추론하면 개발자마다 다른 추가 키가 산출물에 섞일 수 있지만, 이름을 설정에 두면 타입 생성의 입력을 코드와 함께 관리할 수 있다.

2026년 8월 9일 Linux, Node.js 22.18.0, npm 9.2.0, Wrangler 4.120.0, TypeScript 5.9.2로 이 동작을 통제 비교했다. 확인 범위는 로컬 타입 생성과 TypeScript 검사까지다. Cloudflare 계정, 배포, 원격 secret 존재 여부는 검증하지 않았다.

20초 핵심 요약

  • 무엇: secrets.required에 값이 아닌 secret 이름을 선언해 worker-configuration.d.ts의 입력으로 사용한다.
  • 왜: 로컬 비밀 파일 추론에 의존하면 CI에서 타입이 빠지거나 파일의 추가 키가 산출물에 섞일 수 있다.
  • 어떻게: 다중 환경 설정으로 타입을 생성한 뒤 wrangler types --checktsc --noEmit을 차례로 실행한다.

비밀 파일 대신 이름 목록을 타입 생성의 원본으로 둔다

최소 설정은 다음과 같다. top-level에는 공통으로 필요한 API_KEY를 두고, production 환경에는 그 환경이 요구하는 전체 목록을 다시 적는다. secrets는 환경에 상속되는 설정이 아니므로 named environment마다 필요한 이름을 명시한다.

{
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2026-08-08",
  "secrets": {
    "required": ["API_KEY"]
  },
  "env": {
    "production": {
      "secrets": {
        "required": ["API_KEY", "PROD_ONLY"]
      }
    }
  }
}

secrets.required에는 값이 아니라 이름만 들어간다. 설정의 어느 레벨에든 secrets가 있으면 wrangler types.dev.vars.env의 이름 추론을 멈추고 선언된 목록을 사용한다. 이는 Wrangler configuration의 Secrets 계약required secrets 변경 로그에 명시된 동작이다.

실제 값은 로컬 개발에서는 .dev.vars 또는 .env, 배포된 Worker에서는 별도의 secret 관리 경로로 공급한다. 민감한 값을 plaintext vars에 넣어 타입을 얻는 우회는 피해야 한다. 값 공급과 보관 방식은 Cloudflare Workers secrets 문서에서 별도로 확인할 수 있다.

현재 Wrangler v4에서 런타임 타입을 제외하고 바인딩 타입만 만들려면 다음 명령을 사용한다.

npx wrangler types worker-configuration.d.ts --include-runtime false

Planner가 제안했던 --x-include-runtime false는 Wrangler 4.120.0에서 더는 실험 플래그가 필요하지 않다는 오류와 종료 코드 1을 냈다. 현행 옵션은 --include-runtime false다. 런타임 타입도 필요하다면 기본값이 true이므로 이 옵션을 뺀다. 생성 파일은 TypeScript 프로젝트에 포함해야 하며, 이 절차는 Cloudflare Workers TypeScript 문서에 설명돼 있다.

파일이 없어도 선언한 이름과 환경별 타입이 생성됐다

.dev.vars 추론 대조군은 파일에 있던 API_KEY, PROD_ONLY, EXTRA_IN_FILE을 모두 필수 string으로 만들었다. 같은 Worker를 secrets.required 설정으로 바꾸자 추가 파일 키는 사라지고 전체 환경 집계 타입에는 API_KEY: string, PROD_ONLY?: string만 남았다.

다음은 .dev.vars.env가 모두 없음을 확인한 뒤 타입을 생성하고, 같은 설정으로 최신성을 검사한 실제 연속 출력이다. 명령에는 secret 값을 넣지 않았고, 공개하면 안 되는 Wrangler 로그 경로와 ANSI 색상만 원문에서 제거했다.

$ ../node-v22.18.0-linux-x64/bin/node node_modules/wrangler/bin/wrangler.js types worker-required.d.ts --config wrangler.required.jsonc --include-runtime false
⛅️ wrangler 4.120.0
────────────────────
Generating project types...

interface __BaseEnv_Env {
    API_KEY: string;
    PROD_ONLY?: string;
}
declare namespace Cloudflare {
    interface GlobalProps {
        mainModule: typeof import("./src/index");
    }
    interface ProductionEnv {
        API_KEY: string;
        PROD_ONLY: string;
    }
    interface Env extends __BaseEnv_Env {}
}
interface Env extends __BaseEnv_Env {}

✨ Types written to worker-required.d.ts

📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.

$ test ! -e .dev.vars -a ! -e .env
$ ../node-v22.18.0-linux-x64/bin/node node_modules/wrangler/bin/wrangler.js types worker-required.d.ts --config wrangler.required.jsonc --include-runtime false --check
⛅️ wrangler 4.120.0
────────────────────
✨ Types at worker-required.d.ts are up to date.

$ ../node-v22.18.0-linux-x64/bin/node node_modules/wrangler/bin/wrangler.js types worker-required.d.ts --config wrangler.stale.jsonc --include-runtime false --check
⛅️ wrangler 4.120.0
────────────────────
✘ [ERROR] Types at worker-required.d.ts are out of date. Run `wrangler types` to regenerate.

EXIT generate=0 no_secret_files=0 check_fresh=0 check_stale=1

Linux와 Node 22.18.0에서 secret 파일 없이 타입을 생성하고 최신성 검사 종료 0과 1을 확인한 터미널

test의 종료 상태 0은 두 파일이 없었다는 뜻이고, 생성과 최신성 검사의 0은 같은 설정에서 산출물이 일치했다는 뜻이다. stale 설정에는 NEW_SECRET을 추가했으므로 기존 산출물 검사가 1로 끝났다. 생성된 .d.ts에서 실험용 secret 값 문자열을 검색한 결과도 0건이었지만, 이 결과를 모든 로딩·배포 경로의 유출 방지 보장으로 확대할 수는 없다.

PROD_ONLY?는 production에서 선택이라는 뜻이 아니다

Wrangler는 기본적으로 top-level과 모든 named environment의 binding을 집계한다. 일부 환경에만 있는 binding은 공통 Env에서 optional이 되므로 PROD_ONLY?: string이 생성된다. 반면 위 출력의 ProductionEnv에서는 PROD_ONLY: string이다. 이 다중 환경 집계 규칙은 공식 변경 로그Wrangler types 명령 문서에서 확인할 수 있다.

production만 대상으로 생성할 때도 해당 속성은 필수다.

npx wrangler types worker-configuration.d.ts --env production --include-runtime false

공통 코드가 env.PROD_ONLY를 조건 없이 읽는다면 optional을 캐스트로 지우기보다 환경 분기, 런타임 가드, 환경별 진입점 가운데 배포 구조에 맞는 방법을 택해야 한다. 여러 환경이 같은 코드를 공유하는데 production 전용 생성만 CI에 두면 다른 환경의 누락을 가릴 수 있다.

--strict-vars false도 이 문제를 해결하지 않는다. 이 옵션은 secret 필수 여부가 아니라 plaintext vars의 타입 엄격도를 제어한다. 공식 CLI 문서의 설명처럼 통제 비교에서도 기본값은 MODE: "production" | "development", false는 MODE: string을 만들었다. secret의 ?는 strictVars가 아니라 환경별 이름 분포에서 결정됐다.

이름 누락은 생성 뒤 TypeScript 검사에서 드러난다

secrets.required에서 PROD_ONLY를 빼도 wrangler types 자체는 성공한다. 생성기는 코드 사용을 역으로 추론하지 않고 설정에 선언된 이름으로 타입을 만들기 때문이다. 코드가 env.PROD_ONLY를 계속 참조한 상태에서 누락 설정으로 생성하고 tsc --noEmit을 실행한 원문은 다음과 같다.

$ ../node-v22.18.0-linux-x64/bin/node node_modules/wrangler/bin/wrangler.js types worker-missing.d.ts --config wrangler.missing.jsonc --include-runtime false
⛅️ wrangler 4.120.0
────────────────────
Generating project types...

interface __BaseEnv_Env {
    API_KEY: string;
}
declare namespace Cloudflare {
    interface GlobalProps {
        mainModule: typeof import("./src/index");
    }
    interface Env extends __BaseEnv_Env {}
}
interface Env extends __BaseEnv_Env {}

✨ Types written to worker-missing.d.ts

📣 Remember to rerun 'wrangler types' after you change your wrangler.jsonc file.

$ ../node-v22.18.0-linux-x64/bin/node node_modules/typescript/bin/tsc --pretty false --noEmit
src/index.ts(3,63): error TS2339: Property 'PROD_ONLY' does not exist on type 'Env'.
EXIT types_missing=0 tsc=2

PROD_ONLY 선언 누락 시 타입 생성은 성공하고 TypeScript 검사는 TS2339와 종료 2로 실패한 터미널

생성 0과 tsc 2의 차이가 진단 지점이다. 이 실패는 설정의 이름 선언과 코드 참조가 어긋났음을 보여줄 뿐, 원격 Worker에 실제 값이 없거나 값이 잘못됐음을 검사하지 않는다.

CI에서는 최신성과 코드 참조를 두 단계로 검사한다

생성 파일을 저장소에 유지한다면 먼저 --check로 현재 설정과 산출물이 같은지 읽기 전용으로 검사하고, 이어서 TypeScript가 생성된 Env와 코드 참조를 비교하게 한다.

npx wrangler types worker-configuration.d.ts --include-runtime false --check
npx tsc --noEmit

wrangler types --check는 파일을 다시 쓰지 않고 최신 여부를 검사하며, 최신이면 0, 불일치하면 1로 종료한다. 이 계약은 --check 변경 로그현재 Wrangler types 문서에 명시돼 있고, 앞의 실제 출력에서도 같은 결과가 나왔다.

판정 책임을 나누면 실패 원인도 분명해진다.

  • wrangler types --check가 1이면 설정에 비해 .d.ts가 오래됐다.
  • tsc --noEmit이 TS2339로 실패하면 코드가 생성된 Env에 없는 이름을 참조한다.
  • 두 검사가 통과해도 원격 환경의 secret 값 존재·유효성·권한은 확인되지 않았다.

팀이 CI에서 타입을 재생성하고 변경분을 따로 확인하는 정책이라면 git diff --exit-code -- worker-configuration.d.ts를 보조 검사로 둘 수 있다. 최신성 확인만 필요하다면 쓰기 없는 공식 CLI 옵션이 더 직접적이다.

되돌리면 로컬 파일 추론으로 돌아간다

도입을 되돌리는 방법은 설정에서 secrets.required 블록을 제거하는 것이다. 제거 즉시 타입 생성은 .dev.vars.env의 키 추론에 다시 의존한다. CI에 파일이 없으면 secret 타입이 빠질 수 있고, 개발 파일에만 있던 추가 키가 산출물에 섞일 수 있으므로 삭제 전에 기존 파일이 제공하던 키와 환경별 차이를 보존해야 한다.

채택 조건은 required 이름이 설정에 모두 있고, 생성 파일의 값 문자열 검색이 0건이며, TypeScript 검사와 wrangler types --check가 모두 성공하는 상태다. 공통 코드가 환경 전용 secret을 무조건 참조한다면 구조를 나누거나 런타임 가드를 넣기 전에는 채택을 보류한다. 실제 원격 secret 존재 여부가 배포 조건이라면 이 로컬 절차와 분리해, 외부 변경이 허용되는 배포 단계에서 검증해야 한다.

런타임 타입 패키지의 전환 배경도 필요하다면 Cloudflare Workers Types 마이그레이션 글을 한 번 더 확인할 수 있다.

참고 링크

비슷한 글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다