파이썬 python-dotenv 완벽 가이드: API 키와 환경변수 안전 관리
python-dotenv로 API 키와 설정값을 .env 파일에 분리하고 load_dotenv·os.getenv로 불러오는 방법, .gitignore 보안과 개발·운영 환경 분리 원칙을 설명합니다.

python-dotenv를 사용하면 API 키·데이터베이스 주소처럼 코드에 직접 적으면 안 되는 설정값을 .env 파일로 분리하고, 파이썬에서는 os.getenv()로 읽을 수 있습니다. 핵심은 .env를 Git에 올리지 않고, 운영 환경에서는 서버·배포 플랫폼이 제공하는 환경변수를 우선 사용하는 것입니다.
핵심 요약
pip install python-dotenv로 설치한 뒤 앱 시작 지점에서load_dotenv()를 호출합니다..env에는 실제 비밀값을,.env.example에는 값이 비어 있는 변수 이름만 기록합니다..env는 반드시.gitignore에 추가하고 이미 노출된 키는 파일 삭제만 하지 말고 즉시 폐기·재발급합니다.- 기본 설정은 이미 존재하는 시스템 환경변수를 덮어쓰지 않으므로 개발·운영 설정을 분리하기 좋습니다.
환경변수로 API 키를 분리해야 하는 이유
API 키를 API_KEY="실제키"처럼 소스코드에 적으면 Git 저장소, 화면 공유, 오류 로그, 압축 백업을 통해 뜻밖에 노출될 수 있습니다. 환경변수로 분리하면 코드는 필요한 변수 이름만 알고 실제 값은 실행 환경에서 주입받습니다. 설정을 코드 밖에 두는 방식은 개발·테스트·운영 환경마다 코드를 수정하지 않고 값만 바꿀 수 있다는 장점도 있습니다.
다만 .env는 암호화 금고가 아니라 로컬 개발 편의를 위한 일반 텍스트 파일입니다. 파일 접근 권한과 저장 위치를 관리해야 하며, 운영 서버에서는 호스팅 서비스의 비밀값 관리 기능이나 환경변수 설정을 사용하는 편이 안전합니다.
python-dotenv 설치와 기본 사용법
1단계: 패키지 설치
python -m pip install python-dotenv
가상환경이 활성화된 터미널에서 설치하고, 재현 가능한 프로젝트라면 사용 중인 의존성 관리 방식에 python-dotenv를 기록합니다.
2단계: .env 파일 만들기
OPENAI_API_KEY=replace_with_your_key
DATABASE_URL=sqlite:///app.db
DEBUG=false
등호 앞뒤 공백은 피하고 변수 이름은 대문자와 밑줄로 통일하면 알아보기 쉽습니다. 예제의 값은 설명용이므로 실제 키를 본문·문서·공개 저장소에 넣지 마십시오.
3단계: 파이썬에서 불러오기
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise RuntimeError("OPENAI_API_KEY가 설정되지 않았습니다.")
load_dotenv()는 기본적으로 현재 스크립트와 상위 디렉터리에서 .env를 찾아 값을 os.environ에 추가합니다. 이미 시스템에 같은 변수가 있으면 기본값 override=False에 따라 시스템 환경변수를 유지합니다. 운영 값이 로컬 파일 때문에 바뀌는 일을 예방하는 중요한 동작입니다.
.env 파일 작성법과 값 읽는 방법
| 상황 | 작성 예시 | 주의점 |
|---|---|---|
| 일반 문자열 | APP_NAME=myapp |
민감하지 않은 설정도 동일한 방식으로 관리 가능 |
| 공백 포함 | MESSAGE="hello world" |
따옴표로 감싸는 편이 명확함 |
| 변수 확장 | URL=${DOMAIN}/api |
$DOMAIN이 아니라 중괄호 사용 |
| 빈 문자열 | OPTIONAL_VALUE= |
변수 자체가 없는 경우와 구분 |
| 주석 | # local only |
키나 비밀번호를 주석에 남기지 않기 |
값을 환경에 주입하지 않고 딕셔너리로만 읽고 싶다면 dotenv_values()를 사용할 수 있습니다. 공통 설정과 비밀 설정을 합친 뒤 실제 시스템 환경변수에 가장 높은 우선순위를 주는 패턴도 가능합니다.
import os
from dotenv import dotenv_values
config = {
**dotenv_values(".env.shared"),
**dotenv_values(".env.secret"),
**os.environ,
}
.gitignore로 비밀값 유출 막기
프로젝트 루트의 .gitignore에 실제 비밀값 파일을 명시합니다. 팀원이 필요한 변수 이름을 알 수 있도록 실제 값이 없는 .env.example은 저장소에 포함할 수 있습니다.
# .gitignore
.env
.env.*
!.env.example
# .env.example
OPENAI_API_KEY=
DATABASE_URL=
DEBUG=false
.gitignore는 아직 추적되지 않은 파일을 제외할 뿐, 이미 커밋된 키를 과거 기록에서 자동 삭제하지 않습니다. 키가 한 번이라도 원격 저장소에 올라갔다면 해당 서비스에서 키를 폐기하고 새 키를 발급해야 합니다. 이후 저장소 기록 정리는 별도의 문제로 처리하십시오.
개발·테스트·운영 환경을 나누는 실전 패턴
로컬 개발에서는 .env를 편리하게 사용할 수 있지만, 운영에서는 서버나 클라우드가 제공하는 환경변수를 설정하고 코드에는 동일한 변수 이름을 유지하는 방식이 좋습니다. python-dotenv의 기본 동작은 기존 시스템 변수를 덮어쓰지 않으므로 이 구조와 잘 맞습니다.
| 환경 | 권장 저장 위치 | 코드 동작 |
|---|---|---|
| 로컬 개발 | Git에서 제외한 .env |
load_dotenv()로 로드 |
| 테스트 | 테스트 전용 값 또는 CI 비밀값 | 필요한 값만 명시적으로 주입 |
| 운영 | 호스팅 환경변수·비밀 관리 기능 | os.getenv()로 동일하게 조회 |
Docker로 실행한다면 이미지 안에 .env를 복사하지 말고 실행 시점에 필요한 변수를 주입하십시오. 이미지가 레지스트리에 올라가거나 다른 사람에게 전달될 가능성을 고려해야 합니다.
자주 발생하는 오류와 해결법
os.getenv 결과가 None일 때
.env 위치, 변수 이름의 오탈자, load_dotenv() 호출 순서를 확인합니다. 실행 디렉터리가 달라지는 서비스에서는 Path로 파일 위치를 명시하는 방법이 더 안정적입니다.
from pathlib import Path
from dotenv import load_dotenv
env_path = Path(__file__).resolve().parent / ".env"
load_dotenv(env_path)
값을 바꿨는데 이전 값이 유지될 때
운영체제에 같은 환경변수가 이미 설정돼 있으면 기본 설정에서는 그 값을 우선합니다. 개발 중 의도적으로 파일 값을 우선해야 할 때만 load_dotenv(override=True)를 사용하고, 운영 코드에서 무심코 활성화하지 마십시오.
숫자와 불리언이 문자열로 읽힐 때
환경변수는 문자열입니다. 포트는 int()로 변환하고, 불리언은 허용할 문자열을 정해 명시적으로 판정해야 합니다.
port = int(os.getenv("PORT", "8000"))
debug = os.getenv("DEBUG", "false").lower() in {"1", "true", "yes"}
웹 API 프로젝트에서 설정 누락을 시작 단계에 검증하고 싶다면 Pydantic 설정 모델과 결합할 수 있습니다.
실수 방지 체크리스트
.env가.gitignore에 포함됐는지 확인합니다.git status에서 비밀 파일이 추적되지 않는지 확인합니다..env.example에는 변수 이름만 두고 실제 키를 넣지 않습니다.- 필수값이 없을 때 조용히 진행하지 말고 시작 단계에서 오류를 냅니다.
- 로그·예외 메시지·스크린샷에 키 전체를 출력하지 않습니다.
- 운영 환경에서는 플랫폼 환경변수나 비밀 관리 기능을 우선합니다.
- 노출된 키는 즉시 폐기하고 새로 발급합니다.
override=True는 필요한 개발 상황에서만 제한적으로 사용합니다.
FAQ
1. python-dotenv가 API 키를 암호화해 주나요?
아닙니다. 일반 텍스트인 .env를 환경변수로 읽어 주는 도구입니다. 파일 접근과 Git 제외는 별도로 관리해야 합니다.
2. .env 파일을 저장소에 올려도 비공개 저장소면 괜찮나요?
권장하지 않습니다. 접근 권한 변경, 계정 침해, 로그·백업 복제 가능성이 있으므로 실제 비밀값은 저장소 밖에 두십시오.
3. .env.example은 왜 필요한가요?
팀원이 필요한 변수 이름과 기본 형식을 알 수 있게 하면서 실제 비밀값은 공유하지 않기 위해 사용합니다.
4. load_dotenv는 어디에서 호출해야 하나요?
다른 모듈이 환경변수를 읽기 전인 애플리케이션 시작 지점에서 한 번 호출하는 것이 이해하기 쉽습니다.
5. 환경변수가 이미 있으면 .env 값으로 바뀌나요?
기본값에서는 바뀌지 않습니다. 기존 환경변수가 우선하며, override=True를 명시할 때만 파일 값이 덮어씁니다.
6. 여러 .env 파일을 합칠 수 있나요?
dotenv_values()로 각 파일을 딕셔너리로 읽어 병합할 수 있습니다. 마지막에 병합한 값의 우선순위를 의도적으로 정해야 합니다.
7. FastAPI에서도 사용할 수 있나요?
사용할 수 있습니다. 다만 프로젝트가 커지면 타입 변환과 필수값 검증을 위해 설정 모델을 함께 쓰는 편이 좋습니다.
8. Docker 이미지에 .env를 COPY하면 안 되나요?
비밀값이 이미지 레이어에 남을 수 있으므로 피하십시오. 컨테이너 실행 또는 배포 단계에서 값을 주입하는 방식이 적절합니다.
9. Git에 올린 키를 커밋에서 삭제하면 다시 써도 되나요?
안 됩니다. 복제본이나 기록에 남았다고 가정하고 해당 키를 폐기·재발급해야 합니다.
10. python-dotenv 없이도 환경변수를 읽을 수 있나요?
네. 파이썬 표준 라이브러리의 os.getenv()로 읽을 수 있습니다. python-dotenv는 로컬 .env를 편리하게 불러오는 역할을 합니다.
공식 출처
- python-dotenv 공식 문서 — 설치, 로딩, 우선순위, 파일 형식 확인
- PyPI python-dotenv 프로젝트 — 배포 패키지와 최신 변경 내역 확인
- The Twelve-Factor App: Config — 설정을 환경변수에 두는 원칙 확인
공식 자료 확인일: 2026년 9월 1일. 패키지 동작과 지원 버전은 업데이트될 수 있으므로 설치 전 공식 문서와 PyPI의 최신 릴리스를 다시 확인하십시오.