godotenv для Go: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

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                    

Рекомендаций