파이썬 환경변수가 안 불러와질 때는 먼저 os.getenv() 문제가 아니라 현재 프로세스에 값이 들어왔는지, .env를 실제로 읽었는지, 어떤 환경에서 실행했는지를 순서대로 확인해야 합니다. os.getenv()는 변수가 없으면 기본값을 생략했을 때 None을 반환하므로, .env 파일이 있다는 사실만으로 현재 프로세스에 값이 생기지는 않습니다. 이 글에서는 하드코딩이나 재설치보다 환경변수 부재, load_dotenv() 호출, 파일 경로, 기존 환경변수 우선순위, 실행 환경 차이를 구분하는 방법을 정리합니다.
먼저 None이 의미하는 범위를 좁히기
os.getenv("SERVICE_URL")가 None이라면 현재 프로세스의 환경 매핑에서 키를 찾지 못했다는 뜻입니다. os.environ["SERVICE_URL"]처럼 대괄호로 조회하면 키가 없을 때 KeyError가 발생하므로, 필수 설정을 즉시 중단시킬지 선택적으로 처리할지 의도를 분명히 할 수 있습니다.
import os
service_url = os.getenv("SERVICE_URL")
if not service_url:
raise RuntimeError("SERVICE_URL 환경변수가 필요합니다.")
print("SERVICE_URL is configured:", bool(service_url))
값 자체를 로그에 남기지 말고 존재 여부만 확인하는 방식입니다.
.env가 있어도 load_dotenv()가 필요한 경우
python-dotenv의 load_dotenv()는 .env 값을 읽어 os.environ에 설정합니다. 코드에서 이 호출을 하지 않았다면 프로젝트 폴더에 .env가 있어도 os.getenv()가 자동으로 읽는 것은 아닙니다.
import os
from dotenv import load_dotenv
load_dotenv()
service_url = os.getenv("SERVICE_URL")
if service_url is None:
raise RuntimeError("SERVICE_URL이 설정되지 않았습니다.")
실행 방식에 따라 경로가 달라질 수 있다면 파일을 명시합니다.
from pathlib import Path
from dotenv import load_dotenv
env_path = Path(__file__).resolve().parent / ".env"
load_dotenv(env_path)
기본 호출은 스크립트 디렉터리와 상위 디렉터리에서 .env를 찾지만, 파일명이나 배치 위치를 바꾸었다면 자동 탐색 결과에 기대지 않는 것이 좋습니다.
기존 환경변수와 .env 값의 우선순위
load_dotenv()는 기본적으로 이미 존재하는 환경변수를 덮어쓰지 않습니다. 운영 환경에서 주입한 값이 있는데 로컬 .env 값으로 바뀌지 않는다면 오류가 아니라 기본 우선순위일 수 있습니다.
load_dotenv(override=False) # 기본 동작을 명시
override=True는 .env 값으로 기존 환경변수를 덮어쓰므로, 실행 환경이 제공한 설정을 바꿔도 되는 경우에만 선택합니다.
터미널에서는 되는데 IDE·예약 실행에서는 안 되는 이유
환경변수는 파이썬 프로세스가 시작될 때의 실행 환경과 연결됩니다. 터미널에서 설정한 값이 IDE나 별도 예약 실행 프로세스에 자동으로 동일하게 전달된다고 가정하면 안 됩니다. 실행 파일의 위치, 작업 디렉터리, 프로세스가 상속받는 환경, .env 파일의 실제 경로를 각각 확인해야 합니다.
저라면 다음 순서로 확인합니다.
- 코드의 키 이름과
.env의 키 이름이 정확히 같은지 확인합니다. load_dotenv()가 조회보다 먼저 실행되는지 확인합니다..env의 파일명과 명시한 경로가 실제 배치와 맞는지 확인합니다.- 터미널·IDE·예약 실행기에서 작업 디렉터리와 프로세스 환경을 비교합니다.
- 필수값이 없으면 초기에 명확한 오류로 중단합니다.
비밀값 대신 경로와 존재 여부만 출력하는 진단도 유용합니다.
from pathlib import Path
env_path = Path(__file__).resolve().parent / ".env"
print("cwd:", Path.cwd())
print("env file exists:", env_path.is_file())
설정 검증과 비밀값 보호
애플리케이션 시작 단계에서 필요한 키를 검증하되 실제 비밀값은 로그에 남기지 않아야 합니다.
import os
required = ("SERVICE_URL", "SERVICE_TOKEN")
missing = [name for name in required if not os.getenv(name)]
if missing:
raise RuntimeError(f"필수 환경변수 누락: {', '.join(missing)}")
.env에 비밀값을 넣는다면 저장소에 커밋되지 않도록 .gitignore에 포함하는 것이 기본입니다. 배포 환경에서는 실행 프로세스가 제공하는 환경변수를 기준으로 삼고, 로컬 개발에서만 .env를 보조 수단으로 사용하는 경계를 정해 두면 우선순위 혼란도 줄어듭니다.
결론: 재설치보다 실행 경계를 먼저 확인하기
os.getenv()가 None일 때의 핵심은 패키지를 다시 설치하는 것이 아니라 값이 현재 프로세스에 들어오는 경로를 확인하는 것입니다. load_dotenv() 호출 여부, .env 경로와 파일명, 기존 환경변수 우선순위, 실행 환경의 작업 디렉터리와 상속 환경을 차례로 좁히면 원인을 구분할 수 있습니다.
다음으로는 예약 작업에서 실행 경로와 환경을 함께 기록하는 방법, API 키를 코드에 저장하지 않고 시작 단계에서 검증하는 방법을 살펴볼 수 있습니다. 파이썬 환경변수가 안 읽힐 때: os.getenv() None 원인과 확인 순서도 관련 진단에 참고할 수 있습니다.