Next.js 교재 · 18편 · 환경변수

Next.js 환경변수 — .env.local·NEXT_PUBLIC

접두사 한 번 헷갈리면 DB 비밀번호가 브라우저 번들에 박힌다. 그 일이 일어나는 메커니즘.

환경변수 공개/비공개 영역 분리 컨셉 일러스트

Node.js 17편에서 process.env 의 기본을 봤다. Next.js 는 그 위에 두 가지 규칙을 더 얹는다. ① .env.local 자동 로드, ② NEXT_PUBLIC_ 접두사로 클라이언트 노출 분리. 두 규칙을 모르고 쓰면 서버 비밀이 브라우저로 새 나간다.

이번 편에서 그 두 규칙과 환경별 파일·Vercel 설정·실수 방지법을 정리한다.

1. .env 파일 자동 로드 — 5가지 파일

Next.js 가 자동으로 읽는 파일들. 우선순위 순서.

파일역할git
.env모든 환경 공통 (기본값)커밋 OK (비밀 X)
.env.local로컬 개인 설정 + 비밀절대 금지
.env.developmentnpm run dev 전용상황 따라
.env.productionnpm run build 전용상황 따라
.env.test테스트 전용보통 OK

우선순위 — .env.local 가 가장 강함. 같은 키가 여러 파일에 있으면 .env.local 값이 이긴다. 그래서 비밀은 무조건 여기.

실전 분할 전략.env 에 공유 가능한 기본값 (DB 호스트는 localhost, 포트는 5432 등)을 두고 git 에 커밋. 비밀번호·API 키는 .env.local 에 두고 절대 커밋 X. 팀 신규 입사자는 .env 보고 .env.example 참고해 .env.local 만든다.

2. NEXT_PUBLIC_ 접두사 — 클라이언트 노출 분리

핵심 규칙. NEXT_PUBLIC_ 으로 시작하지 않는 변수는 서버에서만 접근 가능.

# .env.local # 서버 전용 (클라이언트 번들에 안 들어감) DATABASE_URL=postgres://... JWT_SECRET=super-secret-32-chars OPENAI_API_KEY=sk-abc123... # 클라이언트도 사용 (브라우저 번들에 박힘 → 공개됨) NEXT_PUBLIC_API_URL=https://api.example.com NEXT_PUBLIC_GA_ID=G-XXXXX NEXT_PUBLIC_SITE_URL=https://my-site.com
// 서버 컴포넌트 또는 API Route — 둘 다 OK import { db } from '@/lib/db'; const url = process.env.DATABASE_URL; // ✅ 서버에서만 const apiUrl = process.env.NEXT_PUBLIC_API_URL; // ✅ 가능 // 클라이언트 컴포넌트 ('use client') 'use client'; function Comp() { console.log(process.env.DATABASE_URL); // ❌ undefined (보안 차단) console.log(process.env.NEXT_PUBLIC_API_URL); // ✅ 사용 가능 }
가장 큰 사고 1위 — DB URL·API 키에 NEXT_PUBLIC_ 접두사를 실수로 붙이는 것. 그 순간 빌드 결과 .js 파일에 평문으로 박혀 모든 방문자 브라우저가 다운로드. GitHub Actions·Vercel build 캐시에도 영구 저장. NEXT_PUBLIC_ 은 명시적 신청서로 생각할 것.

3. 빌드 타임 vs 런타임 — Next 의 미묘한 차이

Node.js 와 다른 가장 큰 점 — NEXT_PUBLIC_ 변수는 빌드 타임에 박힌다.

// page.tsx 안에서 console.log(process.env.NEXT_PUBLIC_API_URL); // → 빌드 결과 .js 파일에서는 console.log("https://api.example.com"); // 평문 치환

그래서 — NEXT_PUBLIC 변수를 바꾸려면 재빌드 필수. .env.local 만 바꾸고 npm start 다시 해도 옛 값이 그대로. npm run build 다시 돌려야.

서버 전용 변수는 반대로 런타임 — 그래서 Vercel 같은 환경에서 환경변수만 바꾸고 재배포 없이 적용 가능.

4. Vercel·호스팅 환경에서

로컬은 .env.local, production 은 어떻게? 호스팅 플랫폼 UI 에서 직접 입력. .env.local 은 절대 production 에 안 올라간다 (의도된 격리).

플랫폼설정 위치
VercelProject · Settings · Environment Variables
NetlifySite · Settings · Build & deploy · Environment
CloudflareWorkers · Settings · Variables
Dockerdocker run -e KEY=value 또는 docker-compose env_file

Vercel 은 환경(Production · Preview · Development) 별로 다른 값 가능 — 가장 자주 쓰는 기능. Preview 는 staging DB, Production 은 진짜 DB.

5. 검증 — Zod 로 시작 시 한 번

Node.js 17편의 패턴과 동일. Next.js 에서도 그대로.

// lib/env.ts import { z } from 'zod'; const Env = z.object({ // 서버 전용 DATABASE_URL: z.string().url(), JWT_SECRET: z.string().min(32), OPENAI_API_KEY: z.string().startsWith('sk-'), // 공개 OK NEXT_PUBLIC_API_URL: z.string().url(), }); const parsed = Env.safeParse(process.env); if (!parsed.success) { console.error('환경변수 오류:', parsed.error.flatten().fieldErrors); throw new Error('Invalid environment'); } export const env = parsed.data;

특별히 t3-env 라는 Next.js 특화 패키지가 인기 — 서버·클라이언트 변수를 분리해 검증하고, 클라이언트 컴포넌트에서 서버 변수 접근 시 에러까지 자동. 더 안전한 진화판.

요약 — 18편 좌표

여기까지 정리. .env.local 이 비밀 보관소, git 절대 금지. NEXT_PUBLIC_ 접두사 = 클라이언트 노출 신청서 — DB URL·시크릿엔 절대 금지. NEXT_PUBLIC 은 빌드 타임에 박혀 변경 시 재빌드 필요, 서버 변수는 런타임이라 환경변수만 바꿔 재시작. Vercel 은 환경별 다른 값 가능. Zod·t3-env 로 시작 시 검증 한 번. 다음 편에서 인증 — NextAuth.js(Auth.js).

다음 편 예고 — 인증 패턴

NextAuth.js (Auth.js) v5 기본 세팅. 19편.

© 2026 주나이테크(주) @JUNAITECH