← 전체 글로 돌아가기

Next.js

Next.js 환경변수가 브라우저에서 비어 있던 원인 추적기

로컬에서는 보이는데 배포 화면에서만 API 주소가 사라졌던 문제를 빌드 시점과 실행 시점으로 나눠 확인한 기록입니다.

화면에만 빈 문자열이 찍혔다

관리자 화면에서 API 주소를 보여 주는 작은 진단 문구가 로컬에서는 정상인데 배포본에서는 빈 문자열이었습니다. 서버 로그에는 값이 있었기 때문에 처음에는 프록시 설정을 의심했습니다. 실제 문제는 브라우저 코드에서 process.env.INTERNAL_API_URL을 읽고 있었던 점이었습니다.

Next.js에서 브라우저 번들에 들어가는 환경변수는 NEXT_PUBLIC_ 접두사가 필요합니다. 접두사를 붙이는 것만으로 끝나지 않고, 변경 뒤에는 새 빌드가 필요하다는 것도 헷갈렸습니다.

확인 순서를 바꿨다

컨테이너 안의 실행 환경과 브라우저가 받은 자바스크립트는 서로 다른 층입니다. 다음처럼 서버에서 먼저 값의 존재 여부만 확인했습니다. 비밀값 자체를 로그에 남기지는 않았습니다.

printenv | grep -E '^(NEXT_PUBLIC_API_BASE|INTERNAL_API_URL)=' | sed 's/=.*/=<set>/'
npm run build

그다음 클라이언트 컴포넌트의 참조를 다음처럼 고쳤습니다.

const apiBase = process.env.NEXT_PUBLIC_API_BASE ?? '';

INTERNAL_API_URL은 서버 전용 코드에만 남겼습니다. 브라우저로 보내도 되는 값과 안 되는 값을 .env.example에 주석으로 구분해 두니 다음 배포 때 판단이 빨라졌습니다.

배포에서 놓친 한 가지

이미 실행 중인 컨테이너에 환경변수만 추가하고 재시작하면 될 것이라고 생각했지만, 클라이언트 값은 빌드 결과에 치환됩니다. 그래서 배포 단계에 환경변수 주입과 이미지 빌드를 함께 묶었습니다.

docker compose build --no-cache web
docker compose up -d web
curl -fsS https://example.com/health

no-cache는 매번 쓸 필요는 없지만, 이번처럼 값이 번들에 들어갔는지 확인하는 동안에는 이전 레이어의 오해를 줄이는 데 도움이 됐습니다.

다음부터 보는 기준

  • 브라우저에서 필요한 값인가, 서버에서만 필요한 값인가?
  • NEXT_PUBLIC_ 값 변경 뒤 새 빌드를 했는가?
  • 로그에는 값이 아니라 설정 여부만 남겼는가?
  • 배포 후 실제 HTML과 브라우저 네트워크 요청을 함께 확인했는가?

환경변수 문제는 이름 하나의 오타처럼 보여도 빌드 경계를 모르면 오래 붙잡게 됩니다. 이제는 서버 프로세스의 환경과 브라우저 번들을 따로 검사하는 것으로 시작합니다.