빠른 시작
5분 안에 env 라이브러리를 시작하세요. 설치부터 실제 사용까지.
설치
bash
go get github.com/cybergodev/env팁
Go 1.25+
.env 파일 생성
프로젝트 루트 디렉터리에 .env 파일을 생성합니다:
bash
# 데이터베이스 설정
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=secret
# 애플리케이션 설정
DEBUG=true
APP_NAME=myapp
LOG_LEVEL=info
# 다중 값(쉼표 구분)
ALLOWED_HOSTS=localhost,example.com,api.example.com최소 사용법
go
package main
import (
"fmt"
"github.com/cybergodev/env"
)
func main() {
// .env 파일을 로드하고 시스템 환경에 적용
if err := env.Load(".env"); err != nil {
panic(err)
}
// 환경 변수 가져오기
host := env.GetString("DB_HOST", "localhost")
port := env.GetInt("DB_PORT", 5432)
fmt.Printf("Server: %s:%d\n", host, port)
}두 가지 사용 모드
env는 두 가지 사용 방식을 제공합니다:
| 모드 | 사용법 | 적용 시나리오 |
|---|---|---|
| 글로벌 모드 | env.Load() + env.GetString() | 단순 애플리케이션, 스크립트, 빠른 프로토타입 |
| 인스턴스 모드 | env.New() + loader.GetString() | 다중 인스턴스, 테스트 격리, 세밀한 수명 제어 |
글로벌 모드는 패키지 수준 함수를 사용하며, 내부적으로 기본 Loader 싱글톤을 유지합니다. env.Load() 호출 이후 모든 env.GetXxx()는 해당 인스턴스를 자동으로 사용합니다. 인스턴스 모드는 env.New()로 독립적인 Loader를 생성하며, 격리가 필요하거나 여러 구성을 동시에 관리해야 하는 시나리오에 적합합니다.
이 문서의 예제는 기본적으로 글로벌 모드를 사용합니다. 인스턴스 모드의 완전한 사용법은 다중 환경 구성 섹션을 참조하세요.
값 읽기 - 모든 타입
기본 타입
go
// === 기본값 포함 ===
// 문자열 - 찾지 못한 경우 기본값 "localhost" 반환
host := env.GetString("HOST", "localhost")
// 정수 (int64) - 찾지 못한 경우 기본값 8080 반환
port := env.GetInt("PORT", 8080)
// 불리언 - 찾지 못한 경우 기본값 false 반환
debug := env.GetBool("DEBUG", false)
// 시간 간격 - 찾지 못한 경우 기본값 30s 반환
timeout := env.GetDuration("TIMEOUT", 30*time.Second)
// === 기본값 미포함 ===
// 문자열 - 찾지 못한 경우 빈 문자열 "" 반환
host := env.GetString("HOST")
// 정수 (int64) - 찾지 못한 경우 0 반환
port := env.GetInt("PORT")
// 불리언 - 찾지 못한 경우 false 반환
debug := env.GetBool("DEBUG")
// 시간 간격 - 찾지 못한 경우 0 반환
timeout := env.GetDuration("TIMEOUT")키 이름 해석
라이브러리는 다양한 키 이름 접근 방식을 지원합니다:
go
// JSON: {"app": {"name": "myapp"}}
// 저장 형태: APP_NAME=myapp
// 다음 방식 모두 해당 값에 접근 가능
name := env.GetString("APP_NAME") // 플랫 키 이름(권장)
name := env.GetString("app.name") // 점 표기 경로(자동 변환)
name := env.GetString("APP.NAME") // 대문자 점 표기 경로해석 규칙:
- 정확한 매칭: 정확한 키 이름
KEY를 먼저 찾습니다 - 대문자 변환: 소문자 키 이름은 대문자 버전을 시도합니다
key→KEY - 경로 해석: 점 표기 경로를 밑줄로 변환합니다
app.name→APP_NAME
불리언 값 지원
GetBool은 다음 값을 지원합니다(대소문자 구분 안 함):
| 참 값 | 거짓 값 |
|---|---|
true, 1, yes, on, enabled | false, 0, no, off, disabled |
슬라이스 타입
go
// 문자열 슬라이스
hosts := env.GetSlice[string]("HOSTS", []string{"localhost"})
// 정수 슬라이스(int, int64, uint, uint64 지원)
ports := env.GetSlice[int64]("PORTS", []int64{80, 443})
portsInt := env.GetSlice[int]("PORTS") // int 타입도 지원
// 부동소수점 슬라이스
rates := env.GetSlice[float64]("RATES", []float64{0.1, 0.2})
// 불리언 슬라이스
flags := env.GetSlice[bool]("FLAGS", []bool{true, false})
// Duration 슬라이스
timeouts := env.GetSlice[time.Duration]("TIMEOUTS")해석 순서:
- 인덱스 키
KEY_0,KEY_1,KEY_2...를 먼저 찾습니다 - 인덱스 키가 없으면
KEY의 값을 쉼표로 구분하여 해석합니다
go
// 방식 1: 인덱스 키(권장)
// HOSTS_0=localhost
// HOSTS_1=example.com
hosts := env.GetSlice[string]("HOSTS") // ["localhost", "example.com"]
// 방식 2: 쉼표 구분
// PORTS=80,443,8080
ports := env.GetSlice[int64]("PORTS") // [80, 443, 8080]확인 및 검색
go
// 키 존재 여부 확인
value, exists := env.Lookup("API_KEY")
if !exists {
// 키가 존재하지 않음
}
// 모든 키 가져오기
keys := env.Keys()
// 모든 키-값 쌍 가져오기
all := env.All()
// 변수 개수 가져오기
count := env.Len()보안 값
go
secret := env.GetSecure("API_KEY")
if secret != nil {
defer secret.Release()
// 원본 값 가져오기(암호화/복호화, API 호출 등 평문이 필요한 경우에만 호출)
value := secret.Reveal()
// 로그용 마스크 사용(유출 방지)
log.Printf("API Key: %s", secret.Masked()) // 출력: [SECURE:32 bytes]
}구조체 매핑
태그를 사용하여 환경 변수를 구조체에 매핑합니다:
go
package main
import (
"fmt"
"time"
"github.com/cybergodev/env"
)
type Config struct {
Host string `env:"DB_HOST" envDefault:"localhost"`
Port int64 `env:"DB_PORT" envDefault:"5432"`
Password string `env:"DB_PASSWORD"`
Debug bool `env:"DEBUG" envDefault:"false"`
Timeout time.Duration `env:"TIMEOUT" envDefault:"30s"`
Hosts []string `env:"ALLOWED_HOSTS"`
}
func main() {
env.Load(".env")
var cfg Config
if err := env.ParseInto(&cfg); err != nil {
panic(err)
}
fmt.Printf("%+v\n", cfg)
}상세
구조체 매핑 가이드를 참조하세요.
구성 프리셋
라이브러리는 서로 다른 시나리오에 적합한 네 가지 프리셋 구성을 제공합니다:
| 프리셋 | 용도 | 특징 |
|---|---|---|
DefaultConfig() | 일반 시나리오 | 안전한 기본값, 대부분의 상황에 적합 |
DevelopmentConfig() | 개발 환경 | 느슨한 제한, 덮어쓰기 허용 |
TestingConfig() | 테스트 환경 | 타이트한 제한, 덮어쓰기 허용, 단위 테스트에 적합 |
ProductionConfig() | 프로덕션 환경 | 엄격한 검증 + 감사 로그 |
go
// 개발 환경 - 느슨한 제한
cfg := env.DevelopmentConfig()
// 테스트 환경 - 타이트한 제한
cfg := env.TestingConfig()
// 프로덕션 환경 - 엄격한 검증 + 감사 로그
cfg := env.ProductionConfig()프리셋 상세 비교
| 기능 | Default | Development | Testing | Production |
|---|---|---|---|---|
| 이미 존재하는 변수 덮어쓰기 | ✗ | ✓ | ✓ | ✗ |
| 파일이 없을 때 오류 | ✗ | ✗ | ✗ | ✓ |
| 감사 로그 | ✗ | ✗ | ✗ | ✓ |
| YAML 구문 | ✗ | ✓ | ✗ | ✗ |
| 파일 크기 제한 | 2MB | 10MB | 64KB | 64KB |
| 최대 변수 수 | 500 | 500 | 50 | 50 |
| 금지 키 검사 | ✓ | ✓ | ✓ | ✓ |
| 값 검증 | ✓ | ✓ | ✓ | ✓ |
팁
- 개발 환경:
DevelopmentConfig()사용, 빠른 반복을 위해 느슨한 제한 - 테스트 환경:
TestingConfig()사용, 테스트 격리를 위해 덮어쓰기 허용 - 프로덕션 환경:
ProductionConfig()사용, 감사 및 엄격한 검증 활성화
다중 환경 구성
환경별 로드
go
// 환경에 따라 구성 파일 결정
goEnv := os.Getenv("GO_ENV")
if goEnv == "" {
goEnv = "development"
}
// 한 번의 호출로 모든 구성 파일 로드(순서대로, 나중에 로드된 것이 먼저 로드된 것을 덮어씀)
env.Load(".env", ".env."+goEnv, ".env.local")Loader 인스턴스 사용
더 많은 제어가 필요할 때는 Loader 인스턴스를 사용합니다:
go
package main
import (
"fmt"
"github.com/cybergodev/env"
)
func main() {
// 구성 생성
cfg := env.ProductionConfig()
cfg.RequiredKeys = []string{"DB_HOST", "API_KEY"}
// 로더 생성
loader, err := env.New(cfg)
if err != nil {
panic(err)
}
defer loader.Close()
// 파일 로드(순서대로, 나중에 로드된 것이 먼저 로드된 것을 덮어씀)
if err := loader.LoadFiles(".env", ".env.production"); err != nil {
panic(err)
}
// 필수 키 검증
if err := loader.Validate(); err != nil {
panic(err)
}
// 사용
host := loader.GetString("DB_HOST")
fmt.Println("Host:", host)
}다중 파일 및 다중 형식
다중 파일 로드
순서대로 로드하며, 나중에 로드된 것이 먼저 로드된 것을 덮어씁니다:
go
env.Load(".env", "config.json", "config.yaml")go
loader.LoadFiles(".env", ".env.local")다중 형식 지원
파일 형식을 자동으로 감지합니다:
go
loader.LoadFiles("config.env", "settings.json", "secrets.yaml")지원 형식
| 형식 | 확장자 | 감지 방식 |
|---|---|---|
| .env | .env | 파일 확장자 |
| JSON | .json | 파일 확장자 |
| YAML | .yaml, .yml | 파일 확장자 |
오류 처리
go
import "errors"
err := loader.LoadFiles(".env")
if err != nil {
switch {
case errors.Is(err, env.ErrFileNotFound):
// 파일이 존재하지 않음
case errors.Is(err, env.ErrFileTooLarge):
// 파일이 너무 큼
case errors.Is(err, env.ErrSecurityViolation):
// 금지된 키(실제로는 *SecurityError 반환)
default:
// 기타 오류
}
// 키 형식이 잘못된 경우: 실제로는 *ValidationError 반환, Field=="key"
var valErr *env.ValidationError
if errors.As(err, &valErr) && valErr.Field == "key" {
// 유효하지 않은 키 형식
}
}상세
go
// 파싱 오류 상세 정보
var parseErr *env.ParseError
if errors.As(err, &parseErr) {
fmt.Printf("파일 %s %d번 줄: %v\n", parseErr.File, parseErr.Line, parseErr.Err)
}
// 파일 오류 상세 정보
var fileErr *env.FileError
if errors.As(err, &fileErr) {
fmt.Printf("파일 %s 작업 %s 실패: %v\n", fileErr.Path, fileErr.Op, fileErr.Err)
}
// 보안 오류 상세 정보
var secErr *env.SecurityError
if errors.As(err, &secErr) {
fmt.Printf("보안 오류: %s - %s\n", secErr.Action, secErr.Reason)
}다음 단계
심화 학습
API 레퍼런스
- 패키지 함수 - 패키지 수준 함수 완전한 목록
- Loader API - 로더 메서드
- Config API - 구성 옵션
보안
- 보안 개요 - 보안 아키텍처와 모범 사례
- SecureValue API - 보안 값 처리