Cloudflare Workers 환경변수, process.env로 안 읽힐 때
왜 문제가 되는가
Node.js 서버나 Vercel 환경에서는 process.env.MY_KEY로 환경변수를 읽는 코드가 별문제 없이 동작한다. 반면 Cloudflare Workers는 요청마다 격리된 런타임에서 실행되고, 환경변수·시크릿·바인딩은 process.env가 아니라 요청 컨텍스트를 통해 주입된다.
@opennextjs/cloudflare를 쓰면 getCloudflareContext()로 이 컨텍스트에 접근할 수 있는데, 기존에 process.env 기준으로 짜여 있던 코드를 그대로 옮기면 로컬에서는 되고 배포하면 값이 undefined로 나오는 상황이 생긴다.
사례 1 — 관리자 인증이 프로덕션에서만 실패
관리자 인증에 쓰이는 값을 process.env로 직접 참조하도록 짜여 있던 코드가 있었다. 로컬 개발 서버에서는 .env 파일을 읽어 정상 동작했지만, Cloudflare Workers에 배포한 뒤에는 해당 값이 비어 있는 것처럼 동작해 인증이 실패했다.
Workers 환경에서는 wrangler.toml에 등록한 시크릿이 process.env가 아니라 getCloudflareContext().env를 통해 노출된다. 참조 방식을 getCloudflareContext() 기반으로 바꾼 뒤에야 배포 환경에서도 정상적으로 값을 읽었다.
사례 2 — 위젯이 프로덕션 빌드에서만 안 뜸
Cloudflare Turnstile(봇 방지) 위젯을 붙이면서, 클라이언트에 노출돼야 하는 site key가 프로덕션 빌드에서만 비어 있는 문제를 겪었다. 이 값은 서버 시크릿이 아니라 브라우저에서 위젯을 초기화할 때 바로 필요한 값이라, 빌드 시점에 번들에 포함되어 있어야 했다.
런타임에만 주입되는 환경변수 방식으로는 클라이언트 번들에 값이 들어가지 않았고, next.config.ts에서 빌드 타임에 명시적으로 주입하도록 바꾸고 나서야 프로덕션 빌드에서도 위젯이 정상적으로 렌더링됐다.
값의 성격에 따라 주입 방식을 구분한다
이후로는 환경변수를 추가할 때마다 세 가지로 구분해서 처리한다. ① 서버에서만 쓰이는 시크릿(DB 자격증명, 관리자 토큰 등)은 getCloudflareContext().env로, ② 클라이언트에 그대로 노출돼야 하는 값(공개 API 키, 위젯 site key 등)은 빌드 타임에 번들에 주입되도록, ③ 배포 환경마다 달라져야 하는 값은 wrangler 설정과 CI 배포 스크립트에서 명시적으로 관리한다.
'런타임에 서버에서만 읽히는 값'과 '빌드 시점에 클라이언트 번들에 박혀야 하는 값'을 구분하지 않고 process.env 하나로 퉁치면, 로컬에서는 통과하고 배포 후에만 조용히 깨지는 버그가 반복된다.