godotenv для Go: полное руководство с примерами
Библиотека godotenv — это портативный и легковесный инструмент для загрузки переменных окружения из файлов формата .env в среду выполнения приложений на языке Go. Она вдохновлена одноимённой библиотекой для Ruby и Node.js и следует принципу «12 Factor App», который гласит, что конфигурация должна храниться в переменных окружения. godotenv позволяет разработчикам вынести чувствительные данные (API-ключи, пароли к базам данных, настройки подключения) из исходного кода в отдельный файл, который не попадает в систему контроля версий.
Основная задача библиотеки — упростить управление конфигурацией в процессе разработки. В production-среде переменные окружения обычно задаются через системные механизмы (Docker, Kubernetes, CI/CD пайплайны), но на локальной машине разработчика удобно использовать файл .env. godotenv автоматически считывает этот файл и делает все определённые в нём переменные доступными через стандартную функцию os.Getenv(). Это избавляет от необходимости писать собственный парсер и обрабатывать краевые случаи.
Библиотека поддерживает многострочные значения, комментарии (строки, начинающиеся с #), пустые строки и экранирование специальных символов. Она не имеет внешних зависимостей, кроме стандартной библиотеки Go, что делает её идеальным выбором для микросервисов и консольных утилит. godotenv не переопределяет уже существующие системные переменные окружения, что гарантирует безопасное поведение при развёртывании.
Установка
Для установки библиотеки выполните одну из следующих команд в терминале в корне вашего Go-проекта:
# Установка последней стабильной версии
go get github.com/joho/godotenv
# Если вы используете Go Modules (рекомендуется)
go get github.com/joho/godotenv@latest
После выполнения команды в файле go.mod появится запись о зависимости. Убедитесь, что ваш проект инициализирован с помощью go mod init.
Быстрый старт
Создайте в корне проекта файл .env со следующим содержимым:
# Файл .env
APP_NAME=MySuperApp
DB_HOST=localhost
DB_PORT=5432
DB_USER=admin
DB_PASSWORD=secret123
SECRET_KEY=my-super-secret-key
Теперь напишите простую программу на Go, которая загрузит этот файл и выведет значения переменных:
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
// Загружаем .env файл
err := godotenv.Load()
if err != nil {
log.Fatal("Ошибка загрузки .env файла:", err)
}
// Читаем переменные окружения
appName := os.Getenv("APP_NAME")
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbUser := os.Getenv("DB_USER")
dbPassword := os.Getenv("DB_PASSWORD")
fmt.Printf("Приложение: %s\n", appName)
fmt.Printf("База данных: %s:%s\n", dbHost, dbPort)
fmt.Printf("Пользователь: %s\n", dbUser)
fmt.Printf("Пароль: %s\n", dbPassword)
}
Запустите программу:
go run main.go
Вы должны увидеть вывод с данными из вашего .env файла.
Основные методы и функции
Библиотека godotenv предоставляет несколько ключевых функций для работы с файлами конфигурации. Рассмотрим каждую из них подробно.
1. Load(filenames ...string) error
Сигнатура: func Load(filenames ...string) error
Описание: Загружает переменные из указанных файлов в окружение процесса. Если файлы не указаны, по умолчанию ищет файл .env в текущей рабочей директории. Если файл не найден, возвращает ошибку.
package main
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
func main() {
// Загрузка из файла по умолчанию (.env)
if err := godotenv.Load(); err != nil {
fmt.Println("Файл .env не найден, используем системные переменные")
}
// Загрузка из конкретного файла
if err := godotenv.Load("/etc/myapp/config.env"); err != nil {
fmt.Println("Не удалось загрузить конфигурацию:", err)
}
// Загрузка из нескольких файлов (последующие перезаписывают предыдущие)
godotenv.Load(".env", ".env.local", ".env.production")
fmt.Println("DB_HOST:", os.Getenv("DB_HOST"))
}
2. LoadIfExists(filenames ...string) error
Сигнатура: func LoadIfExists(filenames ...string) error
Описание: Работает аналогично Load(), но не возвращает ошибку, если файл не существует. Полезно для опциональных конфигурационных файлов.
package main
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
func main() {
// Загружаем .env, если он существует, иначе продолжаем без ошибки
godotenv.LoadIfExists(".env", ".env.local")
// Если ни один файл не найден, программа продолжит работу
fmt.Println("API_KEY:", os.Getenv("API_KEY"))
}
3. Overload(filenames ...string) error
Сигнатура: func Overload(filenames ...string) error
Описание: Загружает переменные из файла, перезаписывая уже существующие системные переменные окружения. Обычный Load() не перезаписывает существующие переменные.
package main
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
func main() {
// Устанавливаем системную переменную
os.Setenv("APP_MODE", "production")
// Обычный Load не перезапишет APP_MODE
godotenv.Load(".env")
fmt.Println("После Load:", os.Getenv("APP_MODE")) // Выведет "production"
// Overload принудительно перезапишет
godotenv.Overload(".env")
fmt.Println("После Overload:", os.Getenv("APP_MODE")) // Выведет значение из .env
}
4. Read(filenames ...string) (map[string]string, error)
Сигнатура: func Read(filenames ...string) (map[string]string, error)
Описание: Читает файл и возвращает карту (map) строк, не изменяя текущее окружение процесса. Позволяет получить переменные без их установки в os.Environ.
package main
import (
"fmt"
"github.com/joho/godotenv"
)
func main() {
// Читаем .env в map, не затрагивая окружение
envMap, err := godotenv.Read(".env")
if err != nil {
fmt.Println("Ошибка чтения:", err)
return
}
for key, value := range envMap {
fmt.Printf("%s = %s\n", key, value)
}
// Переменные НЕ установлены в os.Getenv()
fmt.Println("os.Getenv('DB_HOST'):", os.Getenv("DB_HOST")) // Пусто
}
5. Unmarshal(str string) (map[string]string, error)
Сигнатура: func Unmarshal(str string) (map[string]string, error)
Описание: Парсит строку в формате .env и возвращает карту строк. Полезно, когда содержимое файла получено из другого источника (HTTP-запрос, база данных).
package main
import (
"fmt"
"github.com/joho/godotenv"
)
func main() {
envContent := `
# Комментарий
APP_NAME=TestApp
DEBUG=true
DATABASE_URL=postgres://user:pass@localhost:5432/db
`
envMap, err := godotenv.Unmarshal(envContent)
if err != nil {
fmt.Println("Ошибка парсинга:", err)
return
}
fmt.Println("APP_NAME:", envMap["APP_NAME"])
fmt.Println("DEBUG:", envMap["DEBUG"])
fmt.Println("DATABASE_URL:", envMap["DATABASE_URL"])
}
6. Marshal(envMap map[string]string) (string, error)
Сигнатура: func Marshal(envMap map[string]string) (string, error)
Описание: Преобразует карту строк обратно в формат .env. Полезно для генерации конфигурационных файлов программно.
package main
import (
"fmt"
"github.com/joho/godotenv"
)
func main() {
config := map[string]string{
"APP_NAME": "MyApp",
"VERSION": "1.0.0",
"PORT": "8080",
}
envString, err := godotenv.Marshal(config)
if err != nil {
fmt.Println("Ошибка маршалинга:", err)
return
}
fmt.Println("Сгенерированный .env файл:")
fmt.Println(envString)
// Сохраняем в файл
// os.WriteFile(".env.generated", []byte(envString), 0644)
}
7. Exec(filenames []string, cmd []string, stdout, stderr io.Writer) error
Сигнатура: func Exec(filenames []string, cmd []string, stdout, stderr io.Writer) error
Описание: Загружает переменные из файлов и выполняет указанную команду с этими переменными в окружении. Позволяет запускать внешние программы с конфигурацией из .env.
package main
import (
"os"
"github.com/joho/godotenv"
)
func main() {
// Запускаем команду "env" с переменными из .env
err := godotenv.Exec(
[]string{".env"},
[]string{"env"},
os.Stdout,
os.Stderr,
)
if err != nil {
panic(err)
}
}
8. Write(envMap map[string]string, filename string) error
Сигнатура: func Write(envMap map[string]string, filename string) error
Описание: Записывает карту переменных в файл в формате .env. Если файл существует, он будет перезаписан.
package main
import (
"fmt"
"github.com/joho/godotenv"
)
func main() {
config := map[string]string{
"DATABASE_URL": "mysql://user:pass@localhost:3306/mydb",
"CACHE_DRIVER": "redis",
"REDIS_HOST": "127.0.0.1",
}
err := godotenv.Write(config, ".env.production")
if err != nil {
fmt.Println("Ошибка записи:", err)
return
}
fmt.Println("Файл .env.production успешно создан")
}
9. Parse(r io.Reader) (map[string]string, error)
Сигнатура: func Parse(r io.Reader) (map[string]string, error)
Описание: Парсит содержимое из любого io.Reader (файл, строка, HTTP-ответ) и возвращает карту переменных. Это низкоуровневая функция, на которой основаны Read и Unmarshal.
package main
import (
"fmt"
"strings"
"github.com/joho/godotenv"
)
func main() {
data := strings.NewReader(`KEY1=value1
KEY2=value2
# Это комментарий
KEY3=value3 with spaces`)
envMap, err := godotenv.Parse(data)
if err != nil {
fmt.Println("Ошибка парсинга:", err)
return
}
for k, v := range envMap {
fmt.Printf("%s -> %s\n", k, v)
}
}
10. LoadWithOverride(filenames ...string) error
Сигнатура: func LoadWithOverride(filenames ...string) error
Описание: Устаревшая функция. Эквивалентна Overload(). Загружает переменные с принудительной перезаписью существующих.
package main
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
func main() {
os.Setenv("MY_VAR", "old_value")
// Устаревший способ, рекомендуется использовать Overload
godotenv.LoadWithOverride(".env")
fmt.Println("MY_VAR:", os.Getenv("MY_VAR"))
}
Реальный практический пример
Рассмотрим полноценное приложение — HTTP-сервер с подключением к PostgreSQL, использующий godotenv для конфигурации. Создадим структуру проекта:
myapp/
├── .env
├── .env.example
├── main.go
├── config/
│ └── config.go
├── database/
│ └── db.go
└── go.mod
Файл .env (не коммитится в Git):
# Основные настройки
APP_NAME=MyAwesomeAPI
APP_PORT=8080
APP_ENV=development
# База данных
DB_HOST=localhost
DB_PORT=5432
DB_USER=app_user
DB_PASSWORD=strong_password_123
DB_NAME=myapp_db
DB_SSLMODE=disable
# Redis
REDIS Также в библиотеке
Работа с изображениями в Go: resize и crop с библиотекой imaging
Elasticsearch клиент для Swift (iOS/macOS) — полное руководство
Winston для JavaScript (Node.js): полное руководство с примерами
CocoaPods для Swift: полное руководство с примерами
Геолокация и карты в Java: обзор библиотек и инструментов