frontend

Next.js 환경변수 완벽 가이드 — .env.local부터 NEXT_PUBLIC 클라이언트 변수까지

Next.js에서 API 키는 서버에서만 써야 하므로 NEXT_PUBLIC 없이, 브라우저에서도 써야 하면 NEXT_PUBLIC를 붙여야 한다. .env 파일 종류, 서버/클라이언트 변수 구분, 환경별 설정까지 정리했다.

Next.js환경변수.envNEXT_PUBLIC보안
Next.js 프로젝트의 .env.local 파일에 환경변수를 정의하고 서버와 클라이언트 컴포넌트에서 각각 접근하는 코드 예시
  • ·NEXT_PUBLIC_ 접두사: 빌드 시 번들에 인라인으로 포함되어 브라우저에서 접근 가능
  • ·.env.local: Git에 커밋되지 않는 로컬 전용 환경변수 파일
  • ·Next.js 환경변수 우선순위: .env.local > .env.[NODE_ENV].local > .env.[NODE_ENV] > .env
  • ·서버 컴포넌트 환경변수: 런타임에 동적으로 읽히므로 재빌드 없이 값 변경 가능
처음 Next.js 프로젝트에서 API 키를 클라이언트 컴포넌트에서 쓰려고 process.env.API_KEY로 접근했다가 undefined가 나와서 당황했다. NEXT_PUBLIC_ 접두사 없이는 클라이언트에서 접근할 수 없다는 걸 그때 처음 알았다. 반대로 시크릿 키에 NEXT_PUBLIC를 붙였다가 빌드된 JS 번들에 키가 노출될 수 있다는 걸 깨닫고 즉시 제거했다. 어떤 변수가 서버에서만 쓰이는지 클라이언트에서도 써야 하는지를 먼저 구분하는 게 환경변수 설계의 출발점이다.

Next.js 환경변수의 기본 구조 이해하기

Next.js 환경변수와 NEXT_PUBLIC 접두사의 차이

Next.js에서 환경변수는 서버에서만 접근 가능한 변수와 클라이언트에서도 접근 가능한 변수로 나뉜다. 기본적으로 process.env.변수명으로 정의된 환경변수는 서버 사이드에서만 접근할 수 있다. 서버 컴포넌트, API Routes, getServerSideProps, getStaticProps 같은 서버 실행 환경에서만 값을 읽을 수 있다. 클라이언트 컴포넌트나 브라우저에서 실행되는 코드에서 같은 변수를 접근하면 undefined가 반환된다. 클라이언트에서도 환경변수를 쓰려면 변수 이름 앞에 NEXT_PUBLIC_ 접두사를 붙여야 한다. NEXT_PUBLIC_로 시작하는 변수는 Next.js 빌드 과정에서 해당 값이 번들에 인라인으로 포함된다. 브라우저가 JS 파일을 다운로드할 때 이미 값이 코드 안에 들어있기 때문에 클라이언트에서도 접근할 수 있다. 이 구조 때문에 NEXT_PUBLIC_ 변수에는 절대 시크릿 키나 비밀 정보를 넣으면 안 된다. 빌드된 JS 파일을 개발자 도구에서 열면 값이 그대로 보인다. 공개되어도 되는 값, 예를 들어 GA4 측정 ID나 공개 API 엔드포인트 정도만 NEXT_PUBLIC_로 관리해야 한다.

Next.js .env 파일의 종류와 우선순위

Next.js는 여러 종류의 .env 파일을 지원한다. 각 파일은 서로 다른 용도와 우선순위를 갖는다. .env 파일은 모든 환경에서 공통으로 적용되는 기본 값을 담는다. .env.local은 로컬 개발 환경에서만 사용하는 개인 설정 파일로 Git 저장소에 커밋하면 안 된다. 기본 제공되는 .gitignore에 .env.local이 포함되어 있다. .env.development는 개발 환경(npm run dev)에서만 적용되고, .env.production은 프로덕션 빌드(npm run build)에서 적용된다. .env.local이 .env.development나 .env.production보다 우선순위가 높다. 로컬에서 프로덕션 값을 오버라이드해서 테스트할 때 .env.local을 활용할 수 있다. 테스트 환경에서는 .env.test 파일이 사용된다. .env.local은 test 환경에서는 적용되지 않는다는 점에 주의해야 한다. 실무에서는 대부분 .env.local 하나로 로컬 개발에 필요한 값을 관리하고, 프로덕션 환경변수는 배포 서비스의 환경변수 설정 화면에서 관리하는 패턴을 많이 쓴다. 저장소에는 어떤 변수가 필요한지 키만 남긴 .env.example 파일을 올려두는 것이 관례다.

Next.js 환경변수 설정하는 방법

Next.js .env.local에 환경변수를 추가하고 서버에서 사용하는 방법

로컬 개발에서 환경변수를 설정하려면 프로젝트 루트에 .env.local 파일을 만들고 KEY=VALUE 형식으로 작성한다. 값에 공백이나 특수문자가 있으면 큰따옴표로 감싼다. 주석은 # 기호로 시작한다. 서버 컴포넌트나 API Route에서는 process.env.변수명으로 바로 접근할 수 있다. App Router의 서버 컴포넌트는 async 함수이기 때문에 컴포넌트 상단에서 바로 환경변수를 읽을 수 있다. 환경변수가 없는 경우를 대비해서 기본값을 설정하거나 값이 없을 때 명시적으로 오류를 던지는 패턴이 좋다. 개발 중에 값이 누락된 채로 넘어가면 런타임 오류가 나서 디버깅이 어려워진다. 서버 전용 변수를 실수로 클라이언트 컴포넌트에서 참조하면 Next.js가 빌드 시 경고를 출력하거나 런타임에 undefined를 반환한다. 민감한 API 키나 DB 연결 문자열은 반드시 서버에서만 접근하도록 NEXT_PUBLIC_ 없이 관리해야 한다. .env.local 파일은 절대 Git에 올리면 안 되며, .gitignore에 포함되어 있는지 반드시 확인해야 한다.

# .env.local
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
API_SECRET_KEY=your-secret-key
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
NEXT_PUBLIC_API_URL=https://api.example.com

# 서버 컴포넌트에서 사용
// app/page.tsx (서버 컴포넌트)
export default async function Page() {
  const dbUrl = process.env.DATABASE_URL  // 서버에서만 접근 가능
  const gaId = process.env.NEXT_PUBLIC_GA_ID  // 클라이언트에서도 접근 가능
  return <div />
}

Next.js에서 NEXT_PUBLIC 환경변수를 클라이언트에서 사용하는 방법

클라이언트 컴포넌트에서 환경변수를 써야 한다면 변수 이름에 NEXT_PUBLIC_ 접두사를 붙여야 한다. 접두사를 붙이면 Next.js 빌드 타임에 해당 값이 JS 번들에 직접 삽입된다. 클라이언트에서 process.env.NEXT_PUBLIC_GA_ID로 접근하면 빌드 시 G-XXXXXXXXXX 실제 값으로 대체된다. 이 방식의 특성상 NEXT_PUBLIC_ 변수는 빌드 타임에 값이 고정된다. 빌드 후 서버에서 환경변수를 바꿔도 클라이언트 번들 안의 값은 변하지 않는다. 값을 바꾸려면 새로 빌드해야 한다. 서버 컴포넌트에서 process.env를 통해 접근하는 서버 전용 변수는 런타임에 동적으로 읽히기 때문에 재빌드 없이 값을 바꿀 수 있다. 클라이언트에서 환경변수를 전달해야 할 때 서버 컴포넌트에서 값을 props로 넘기는 방식도 있다. 이 방식은 NEXT_PUBLIC_ 없이도 클라이언트 컴포넌트에 값을 전달할 수 있고, 어떤 값이 클라이언트로 전달되는지 명시적으로 통제할 수 있다는 장점이 있다. 민감하지 않은 공개 값은 NEXT_PUBLIC_로, 서버에서만 계산하고 클라이언트로 일부만 전달할 값은 props 패턴을 쓰는 게 좋다.

Next.js 환경별 환경변수 관리

Next.js 개발/프로덕션 환경별 환경변수를 분리하는 방법

로컬 개발과 프로덕션에서 서로 다른 환경변수가 필요한 경우가 많다. 개발 환경에서는 로컬 DB에 연결하고 프로덕션에서는 실제 DB에 연결하는 것이 대표적인 예다. Next.js는 .env.development와 .env.production 파일을 지원한다. .env.development는 npm run dev 실행 시, .env.production은 npm run build와 npm start 실행 시 적용된다. .env 파일에는 개발과 프로덕션 모두에서 공통으로 쓰이는 기본값을 두고, 환경별 파일에서 해당 환경에만 맞는 값을 오버라이드하는 구조로 관리하면 깔끔하다. .env.local은 어떤 환경에서든 가장 높은 우선순위를 갖기 때문에 로컬에서 특정 값을 임시로 오버라이드할 때 편리하다. 프로덕션 환경변수는 .env.production 파일에 민감한 값을 직접 커밋하는 대신, Vercel, Render, Railway 같은 배포 플랫폼의 환경변수 설정에서 관리하는 게 안전하다. CI/CD 파이프라인에서 빌드할 때는 GitHub Secrets이나 Jenkins Credentials를 통해 환경변수를 주입하는 방식을 쓴다.

Next.js 환경변수를 안전하게 관리하는 방법

환경변수 관리에서 가장 중요한 원칙은 시크릿 값이 코드 저장소에 올라가지 않도록 하는 것이다. .env.local과 실제 값이 담긴 .env 파일은 .gitignore에 포함해야 한다. 저장소에는 변수 목록과 간략한 설명만 담은 .env.example 파일을 올려두는 것이 팀 협업 표준이다. 새 팀원이 합류하면 .env.example을 복사해서 .env.local로 만들고 각자 값을 채우면 된다. 서버 컴포넌트에서 환경변수를 검증하는 라이브러리를 쓰면 필수 변수가 누락됐을 때 즉시 오류를 내서 런타임 버그를 방지할 수 있다. zod나 t3-env 같은 라이브러리로 환경변수 스키마를 정의하면 타입 안전성도 확보된다. NEXT_PUBLIC_ 변수는 빌드된 번들에 값이 노출된다는 점을 항상 인지해야 한다. GitHub Actions 같은 CI 환경에서 빌드할 때 NEXT_PUBLIC_ 변수를 Secrets에 저장해도 빌드 결과물에는 실제 값이 포함되기 때문에, 공개되면 안 되는 값은 절대 NEXT_PUBLIC_로 관리해서는 안 된다. 클라이언트에 노출되어도 되는 값만 NEXT_PUBLIC_로, 나머지는 모두 서버 전용으로 관리하는 원칙을 지키는 것이 보안의 기본이다.

자주 묻는 질문

클라이언트 컴포넌트에서 process.env.변수명이 undefined로 나오는 이유가 무엇인가요?+

NEXT_PUBLIC_ 접두사가 없는 환경변수는 서버에서만 접근할 수 있습니다. 클라이언트 컴포넌트에서 쓰려면 변수 이름을 NEXT_PUBLIC_변수명으로 바꾸고 .env.local도 업데이트해야 합니다. 변경 후 개발 서버를 재시작해야 합니다.

.env.local을 수정했는데 값이 반영되지 않으면 어떻게 하나요?+

환경변수 파일을 변경한 후에는 Next.js 개발 서버를 재시작해야 합니다. 변경 사항이 hot reload로는 적용되지 않습니다. npm run dev를 다시 실행하면 업데이트된 환경변수가 로드됩니다.

프로덕션 빌드에서 환경변수를 주입하는 방법이 있나요?+

Vercel을 쓴다면 프로젝트 Settings의 Environment Variables에서 설정합니다. Jenkins나 GitHub Actions로 빌드한다면 파이프라인에서 환경변수를 주입한 상태로 npm run build를 실행하면 됩니다. Jenkins Credentials에 등록한 값을 withCredentials 블록으로 주입하는 방식이 안전합니다.

환경변수가 undefined일 때 기본값을 설정하는 방법이 있나요?+

process.env.변수명 ?? '기본값' 형태로 null 병합 연산자를 쓰거나, process.env.변수명 || '기본값' 형태로 작성하면 됩니다. 필수 변수가 없을 때 명시적으로 오류를 내려면 if (!process.env.변수명) throw new Error('변수명 is required')처럼 빌드 초기에 검증하는 코드를 추가하는 게 좋습니다.

관련 글