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 struct. Existing process environment variables take precedence over file-defined values.

Installation

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

Quick Start

package main

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

func main() {
    // Load .env file and validate required variables
    cfg, err := env.New()
    if err != nil {
        log.Fatal(err)
    }
    
    // Use the configuration
    println(cfg.DatabaseURL)
}

Functions

Load

Reads key=value pairs from a .env file and sets them in the process environment.
pkg/env/env.go:25
func Load(path ...string) error
path
...string
Path to the .env file. If not provided or empty, defaults to .env in the current directory.
Behavior:
  • Existing environment variables are not overwritten
  • Repeated calls with the same path are no-ops and return the cached result
  • Returns nil if the file doesn’t exist (not an error)
  • Supports # for comments
  • Supports quoted values with " or '
  • Strips leading/trailing whitespace from keys and values
Example:
// 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

Loads the .env file and returns a Config populated from the environment.
pkg/env/config.go:29
func New() (*Config, error)
Returns an error if:
  • The .env file cannot be loaded
  • Required variables are missing or empty
Example:
cfg, err := env.New()
if err != nil {
    log.Fatal(err)
}

fmt.Println(cfg.DatabaseURL)

Types

Config

Holds all environment variables required by the application.
pkg/env/config.go:21
type Config struct {
    DatabaseURL string `env:"DATABASE_URL,required"`
}
Tag Format:
  • env:"VAR_NAME" - Optional variable
  • env:"VAR_NAME,required" - Required variable (must be set and non-empty)
Example Configuration:
type Config struct {
    DatabaseURL string `env:"DATABASE_URL,required"`
    LogLevel    string `env:"LOG_LEVEL"`
    Port        string `env:"PORT"`
}

.env File Format

The .env file uses a simple KEY=VALUE format:
# Database configuration
DATABASE_URL=postgres://user:pass@localhost/db

# Optional settings
LOG_LEVEL=debug
PORT="8080"

# Quoted values are supported
SECRET_KEY='my-secret-key'
Format Rules:
  • One variable per line: KEY=VALUE
  • Comments start with #
  • Empty lines are ignored
  • Values can be quoted with " or ' (quotes are stripped)
  • Whitespace around keys and values is trimmed
  • Process environment variables take precedence over file values

Error Handling

The package provides clear error messages for common issues:
// Missing required variables
cfg, err := env.New()
if err != nil {
    // Error: "env: missing required variables: DATABASE_URL, API_KEY"
    log.Fatal(err)
}

// File access errors
if err := env.Load("/invalid/path/.env"); err != nil {
    // Error includes the file path and system error
    log.Fatal(err)
}

Thread Safety

The Load function is thread-safe and uses a mutex to prevent race conditions. Multiple goroutines can safely call Load concurrently.

Best Practices

  1. Call early in main(): Load environment variables before initializing other packages
func main() {
    cfg, err := env.New()
    if err != nil {
        log.Fatal(err)
    }
    
    // Initialize other packages with config
    db.Connect(cfg.DatabaseURL)
}
  1. Don’t commit .env files: Add .env to your .gitignore
# .gitignore
.env
.env.*
!.env.example
  1. Provide an example file: Create .env.example with dummy values
# .env.example
DATABASE_URL=postgres://user:pass@localhost/mydb
LOG_LEVEL=info
  1. Production environments: Use actual environment variables instead of .env files in production

Build docs developers (and LLMs) love