Vite + React SPA - 환경변수 설정
◆환경변수(Environment Variable)란?
환경변수(Environment Variable)는 프로그램의 코드와 설정값을 분리하기 위해 사용하는 값이다.
예를 들어 Supabase의 URL을 코드에 직접 작성할 수도 있다.
const supabaseUrl = 'https://xxxxx.supabase.co'
하지만 실제 프로젝트에서는 다음과 같이 환경변수를 사용하는 것이 좋다.
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
그리고 환경변수 파일에서 실제 값을 관리한다.
VITE_SUPABASE_URL=https://xxxxx.supabase.co
이렇게 하면 코드 자체를 수정하지 않고 환경에 따라 다른 설정값을 사용할 수 있다.
◆환경변수를 사용하는 이유
환경변수를 사용하는 이유는 크게 다음과 같다.
① 환경별 설정을 분리할 수 있다
개발 환경과 운영 환경에서 서로 다른 서버나 DB를 사용할 수 있다.
개발 환경
React → 개발용 서버/DB
운영 환경
React → 운영용 서버/DB
예를 들어 개발 환경에서는:
VITE_API_URL=http://localhost:8080
운영 환경에서는:
VITE_API_URL=https://api.example.com
처럼 서로 다른 값을 사용할 수 있다.
② 코드와 설정을 분리할 수 있다
소스 코드에 URL이나 설정값을 직접 작성하지 않아도 된다.
const apiUrl = import.meta.env.VITE_API_URL
이렇게 작성하면 실제 URL은 환경변수 파일에서 관리할 수 있다.
③ 민감한 정보를 코드와 분리할 수 있다
서버에서만 사용해야 하는 비밀키도 환경변수로 관리할 수 있다.
예:
SUPABASE_SERVICE_ROLE_KEY=xxxxx
BREVO_API_KEY=xxxxx
다만 환경변수에 넣었다고 해서 무조건 비밀 정보가 되는 것은 아니다.
특히 Vite에서는 VITE_가 붙은 환경변수가 브라우저에서 사용할 수 있도록 빌드 결과에 포함될 수 있기 때문에 주의해야 한다.
◆.env 파일의 종류
Vite 프로젝트에서는 다음과 같은 환경변수 파일을 사용할 수 있다.
.env
.env.local
.env.development
.env.production
파일 이름에 따라 적용되는 환경이 달라질 수 있다.
예를 들어:
npm run dev
↓
development 환경
↓
.env.development
그리고:
npm run build
↓
production 환경
↓
.env.production
과 같이 사용할 수 있다.
◆.env.development와 .env.production은 왜 나누는가?
개발 환경과 운영 환경의 설정값이 다를 수 있기 때문이다.
예를 들어 개발 환경에서는:
VITE_API_URL=http://localhost:8080
운영 환경에서는:
VITE_API_URL=https://api.example.com
을 사용할 수 있다.
즉,
개발 환경
localhost:8080
운영 환경
api.example.com
처럼 서로 다른 서버를 사용하기 위해 환경변수를 분리하는 것이다.
◆두 파일을 반드시 만들어야 할까?
아니다.
.env.development와 .env.production은 반드시 둘 다 만들어야 하는 파일이 아니다.
개발 환경과 운영 환경에서 사용하는 값이 동일하다면 하나의 공통 환경변수 파일을 사용할 수도 있다.
예를 들어 하나의 Supabase 프로젝트를 개발과 운영에서 모두 사용한다면:
VITE_SUPABASE_URL=https://xxxxx.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=xxxxx
와 같이 동일한 값을 사용할 수 있다.
환경변수를 환경별로 나누는 이유는 개발 환경과 운영 환경의 설정값이 다를 수 있기 때문이다.
◆VITE_는 무엇인가?
Vite 프로젝트에서는 브라우저에서 사용할 환경변수를 구분하기 위해 일반적으로 VITE_ 접두사를 사용한다.
예를 들어:
VITE_SUPABASE_URL=https://xxxxx.supabase.co
그리고 React에서는:
import.meta.env.VITE_SUPABASE_URL
로 사용할 수 있다.
반면 다음과 같이 VITE_가 없는 환경변수는:
SUPABASE_SERVICE_ROLE_KEY=xxxxx
브라우저 코드에서 import.meta.env.SUPABASE_SERVICE_ROLE_KEY 방식으로 사용할 수 있는 것이 아니다.
즉, Vite의 클라이언트 코드에 노출할 필요가 있는 값과 서버에서만 사용해야 하는 값을 구분하는 데 VITE_ 접두사를 활용할 수 있다.
◆VITE_SUPABASE_URL은 무엇인가?
다음과 같은 환경변수가 있다고 하자.
VITE_SUPABASE_URL=https://xxxxx.supabase.co
이 값을 처음 보면 “Vercel과 Supabase를 연결하는 키인가?”라고 생각할 수 있다.
하지만 정확하게 말하면 Supabase 프로젝트의 URL이다.
즉, React 애플리케이션에게:
“어느 Supabase 프로젝트에 접속해야 하는가?”
를 알려주는 주소이다.
VITE_SUPABASE_URL
↓
Supabase 프로젝트 주소
↓
https://xxxxx.supabase.co
◆Supabase 연결에는 URL과 Key가 함께 필요하다
React에서 Supabase를 사용하려면 일반적으로 URL과 Publishable Key를 함께 사용한다.
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
)
각 값의 역할은 다음과 같다.
VITE_SUPABASE_URL
↓
어느 Supabase 프로젝트에 접속할 것인가?
VITE_SUPABASE_PUBLISHABLE_KEY
↓
브라우저에서 사용할 공개용 키
전체적인 구조는 다음과 같다.
React
│
├── VITE_SUPABASE_URL
│
└── VITE_SUPABASE_PUBLISHABLE_KEY
│
▼
Supabase
│
▼
PostgreSQL
◆VITE_SUPABASE_PUBLISHABLE_KEY란?
VITE_SUPABASE_PUBLISHABLE_KEY는 브라우저에서 Supabase를 사용하기 위한 공개용 키이다.
예를 들어:
VITE_SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxxxx
그리고 React에서:
const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
)
와 같이 사용한다.
여기서 중요한 점은 Publishable Key는 브라우저에 노출될 수 있다는 것이다.
왜냐하면 VITE_가 붙은 환경변수는 Vite 빌드 과정에서 클라이언트 코드에서 사용할 수 있도록 처리되기 때문이다.
따라서 Publishable Key를 사용하는 것 자체가 보안 취약점은 아니다.
대신 Supabase에서는 RLS(Row Level Security)를 통해 실제 데이터 접근 권한을 제어해야 한다.
브라우저
│
│ Publishable Key
▼
Supabase
│
│ RLS 정책 확인
▼
데이터 접근 허용/차단
즉, Publishable Key 자체가 데이터베이스 접근 권한을 모두 허용하는 것은 아니다.
◆SUPABASE_SERVICE_ROLE_KEY란?
반면 SUPABASE_SERVICE_ROLE_KEY는 완전히 다르게 취급해야 한다.
이 키는 서버 측에서만 사용해야 하는 매우 민감한 키이다.
예:
SUPABASE_SERVICE_ROLE_KEY=xxxxx
이 키는 브라우저의 React 코드에서 사용하면 안 된다.
특히 다음과 같이 작성하면 안 된다.
VITE_SUPABASE_SERVICE_ROLE_KEY=xxxxx
왜냐하면 VITE_를 붙이면 클라이언트 코드에 노출될 수 있기 때문이다.
◆Publishable Key와 Service Role Key의 차이
두 키의 가장 중요한 차이는 사용 위치와 권한이다.
| 구분 | Publishable Key | Service Role Key |
|---|---|---|
| 환경변수 예시 | VITE_SUPABASE_PUBLISHABLE_KEY |
SUPABASE_SERVICE_ROLE_KEY |
| 사용 위치 | 브라우저 / React | 서버 |
VITE_ 사용 |
O | X |
| 브라우저 노출 | 가능 | 절대 금지 |
| RLS | 적용됨 | RLS를 우회할 수 있음 |
| 용도 | 일반적인 클라이언트 Supabase 접근 | 서버의 관리자 수준 작업 |
| 보안 수준 | 공개 가능 | 비밀 유지 필요 |
쉽게 표현하면 다음과 같다.
Publishable Key
↓
브라우저에서 사용
↓
RLS 정책 적용
↓
허용된 데이터만 접근
반면:
Service Role Key
↓
서버에서만 사용
↓
관리자 수준 권한
↓
RLS를 우회할 수 있음
따라서 Service Role Key가 Publishable Key보다 강력한 권한을 가진다.
◆Service Role Key를 React에서 사용하면 안 되는 이유
React 애플리케이션은 최종적으로 사용자의 브라우저에서 실행된다.
따라서 React 코드에 비밀키를 넣으면 사용자가 개발자 도구 등을 통해 해당 값을 확인할 가능성이 있다.
잘못된 예:
VITE_SUPABASE_SERVICE_ROLE_KEY=xxxxx
const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_SERVICE_ROLE_KEY
)
이렇게 하면 Service Role Key가 클라이언트에 노출될 수 있다.
따라서 Service Role Key가 필요한 작업은 서버에서 처리해야 한다.
React
│
│ Publishable Key
▼
Supabase
│
└── 일반적인 데이터 접근
관리자 권한이 필요한 작업은:
React
│
▼
서버 / Edge Function
│
│ Service Role Key
▼
Supabase
와 같은 구조로 처리하는 것이 적절하다.
◆Publishable Key도 아무렇게나 사용해도 되는 것은 아니다
Publishable Key가 공개용이라고 해서 Supabase 테이블을 아무나 수정할 수 있는 것은 아니다.
실제 보안은 RLS 정책이 담당한다.
예를 들어 posts 테이블이 있다고 하자.
React
│
│ Publishable Key
▼
Supabase
│
▼
posts 테이블
이때 RLS 정책을 통해:
SELECT → 허용
INSERT → 특정 사용자만 허용
UPDATE → 작성자만 허용
DELETE → 관리자만 허용
처럼 세부적인 권한을 설정할 수 있다.
따라서 Supabase를 브라우저에서 직접 사용하는 구조에서는 Publishable Key + 적절한 RLS 정책이 핵심이다.
◆.gitignore에 환경변수 파일을 추가한다
실제 환경변수 파일에는 중요한 값이 포함될 수 있으므로 일반적으로 Git에 올리지 않는다.
예:
.env
.env.*
!.env.example
그러면:
.env
.env.development
.env.production
.env.local
등은 Git에서 제외하고,
.env.example
은 Git에 포함할 수 있다.
◆.env.example을 사용하는 이유
팀 프로젝트에서는 다른 개발자가 프로젝트를 실행하기 위해 어떤 환경변수가 필요한지 알아야 한다.
그래서 실제 값은 제거한 .env.example 파일을 Git에 올릴 수 있다.
예:
# .env.example
VITE_SUPABASE_URL=
VITE_SUPABASE_PUBLISHABLE_KEY=
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
BREVO_API_KEY=
MAIL_FROM=
MAIL_FROM_NAME=
HOTEL_INQUIRY_ADMIN_EMAIL=
여기에는 실제 키 값을 작성하지 않는다.
다른 개발자는:
.env.example
↓
.env.development
↓
실제 개발용 값 입력
과 같은 방식으로 사용할 수 있다.
◆Vercel에서는 환경변수를 어떻게 관리하는가?
Vercel에 React 프로젝트를 배포하는 경우에는 실제 운영 환경변수를 Vercel의 프로젝트 설정에서 관리할 수 있다.
예를 들어:
Vercel
↓
Project
↓
Settings
↓
Environment Variables
여기에 다음과 같은 값을 설정할 수 있다.
VITE_SUPABASE_URL
VITE_SUPABASE_PUBLISHABLE_KEY
그리고 서버에서만 사용하는 값은:
SUPABASE_SERVICE_ROLE_KEY
BREVO_API_KEY
등으로 관리한다.
여기서도 중요한 것은 VITE_가 Vercel에서 붙이는 접두사가 아니라 Vite가 클라이언트 환경변수를 구분하기 위해 사용하는 규칙이라는 점이다.
댓글남기기