Skip to main content
The env package loads environment variables from a .env file into the process environment and validates required variables into a typed Config. Existing process environment variables take precedence over file-defined values.

Functions

Load

func Load(path ...string) error
Reads key=value pairs from a .env file and sets them in the process environment. Existing variables are not overwritten. Repeated calls with the same path are no-ops and return the cached result.
path
...string
Path to the .env file. If not provided or empty, defaults to .env in the current directory.
Returns: error - Returns an error if the file cannot be read or parsed. Returns nil if the file does not exist. Behavior:
  • Empty lines and lines starting with # are ignored
  • Quotes (single or double) around values are automatically stripped
  • Existing environment variables are never overwritten
  • Thread-safe with internal caching to prevent duplicate loads
  • Invalid lines are logged as warnings but do not cause errors
Example:
package main

import (
    "log"
    "github.com/aarock1234/go-template/pkg/env"
)

func main() {
    // Load from default .env file
    if err := env.Load(); err != nil {
        log.Fatal(err)
    }

    // Load from custom path
    if err := env.Load(".env.production"); err != nil {
        log.Fatal(err)
    }
}

New

func New() (*Config, error)
Loads the .env file and returns a Config populated from the environment. Required variables that are missing or empty are returned as a single error. Returns: (*Config, error) - A populated Config struct or an error if loading fails or required variables are missing. Example:
package main

import (
    "log"
    "github.com/aarock1234/go-template/pkg/env"
)

func main() {
    config, err := env.New()
    if err != nil {
        log.Fatal(err)
    }

    // Use config fields
    log.Printf("Database URL: %s", config.DatabaseURL)
}

Types

Config

type Config struct {
    DatabaseURL string `env:"DATABASE_URL,required"`
}
Holds all environment variables required by the application. Add a field with an env tag to register a new variable. Tag Format:
  • env:"VAR_NAME" - Optional variable
  • env:"VAR_NAME,required" - Required variable (must be present and non-empty)
Fields:
DatabaseURL
string
required
PostgreSQL database connection URL. Maps to the DATABASE_URL environment variable.
Extending Config: To add new environment variables, add fields to the Config struct with appropriate tags:
type Config struct {
    DatabaseURL string `env:"DATABASE_URL,required"`
    LogLevel    string `env:"LOG_LEVEL"`
    Port        string `env:"PORT,required"`
    APIKey      string `env:"API_KEY"`
}
Example .env file:
# Database configuration
DATABASE_URL=postgres://user:pass@localhost:5432/dbname

# Optional logging
LOG_LEVEL=debug

# Comments are ignored
# Empty lines are also ignored

# Quotes are automatically stripped
API_KEY="secret-key-123"
API_SECRET='another-secret'

Features

Environment Variable Precedence

The package respects existing environment variables. If a variable is already set in the process environment, the value from the .env file is ignored. This allows:
  • Local development with .env files
  • Production deployment with real environment variables
  • Override capability for testing

Thread Safety

All operations are thread-safe. The package uses internal locking to ensure safe concurrent access and prevents race conditions when loading files.

Caching

Loaded files are cached. Calling Load() multiple times with the same path will only read the file once and return the cached result (including errors).

Error Handling

The package distinguishes between different error types:
  • Missing file: Returns nil (not an error)
  • Unreadable file: Returns error
  • Invalid format: Logs warning, continues processing
  • Missing required variables: Returns error with all missing variable names

Build docs developers (and LLMs) love