envconfig
Tutorial

Getting Started

How to get started with this product


Overview
envconfig: Getting Started Workflow 1. Set Environment Variables export MYAPP_PORT=8080 export MYAPP_USER=Kelsey ... 2. Define Config Struct type Specification struct { Port int; User string; ... } 3. Import envconfig go get github.com/kelseyhightower/ envconfig 4. Call envconfig.Process() var s Specification err := envconfig.Process("myapp", &s) err != nil? (process error) Yes Handle Error log.Fatal(err) Check variable names No 5. Use Populated Struct Fields fmt.Println(s.Port, s.User) // s.Timeout, s.Users, s.ColorCodes 6. App Configured & Running Port: 8080 User: Kelsey Rate: 0.5 Timeout: 3m0s Legend Action step envconfig step Decision Success Error

This page walks you through installing envconfig and wiring it up to load your application's configuration from environment variables in minutes. envconfig reads environment variables and automatically populates a Go struct, so you can configure your application at runtime without touching your code. By the end of this tutorial you will have a working Go program that reads typed configuration values—including strings, integers, durations, slices, and maps—directly from the environment.


Prerequisites

Before you begin, make sure you have the following:

  • Go 1.11 or later installed and a working Go module project (go mod init has been run)
  • Basic familiarity with Go structs and the go get command
  • A terminal where you can set environment variables (export on macOS/Linux, set or $env: on Windows PowerShell)

Quick start

The steps below take you from an empty project to a running configuration loader.

  1. Add envconfig to your project

    go get github.com/kelseyhightower/envconfig
    
  2. Set the required environment variables

    export MYAPP_DEBUG=false
    export MYAPP_PORT=8080
    export MYAPP_USER=Kelsey
    export MYAPP_RATE="0.5"
    export MYAPP_TIMEOUT="3m"
    export MYAPP_USERS="rob,ken,robert"
    export MYAPP_COLORCODES="red:1,green:2,blue:3"
    
  3. Create main.go with the code shown in the Examples section below.

  4. Run the program

    go run main.go
    

    You should see your configuration values printed to stdout, confirming that envconfig read them from the environment.


Steps

Follow these steps to build a complete configuration-loading setup from scratch.

Step 1 — Install the library

From inside your Go module directory, run:

go get github.com/kelseyhightower/envconfig

This adds github.com/kelseyhightower/envconfig to your go.mod and go.sum files. You only need to do this once per project.


Step 2 — Define a configuration struct

Create a struct whose fields represent the values your application needs. envconfig maps each field to an environment variable automatically: it uppercases the field name and prepends the application prefix you supply at runtime.

type Specification struct {
    Debug      bool
    Port       int
    User       string
    Users      []string
    Rate       float32
    Timeout    time.Duration
    ColorCodes map[string]int
}

For example, the Port field maps to MYAPP_PORT when you use the prefix "myapp". envconfig handles type conversion for you, so the string "8080" in the environment becomes the integer 8080 in your struct.


Step 3 — Call envconfig.Process

In your main function, declare a zero-value struct and pass a pointer to envconfig.Process along with your chosen prefix:

var s Specification
err := envconfig.Process("myapp", &s)
if err != nil {
    log.Fatal(err.Error())
}

The prefix ("myapp") is prepended to every environment variable name. Using a prefix prevents conflicts with other programs running in the same environment. If Process returns an error—for example because a required variable is missing or a value cannot be converted—it is safe to treat this as a fatal startup error.


Step 4 — Set environment variables and run

Set each variable in your terminal using the PREFIX_FIELDNAME convention, then run your program:

export MYAPP_DEBUG=false
export MYAPP_PORT=8080
export MYAPP_USER=Kelsey
export MYAPP_RATE="0.5"
export MYAPP_TIMEOUT="3m"
export MYAPP_USERS="rob,ken,robert"
export MYAPP_COLORCODES="red:1,green:2,blue:3"

go run main.go

If the program prints your configuration values without error, the setup is working correctly.


Step 5 — (Optional) Add struct tags for richer control

Once the basics work, you can refine behavior with struct tags:

  • envconfig:"MY_VAR" — maps the field to a specific variable name instead of the derived default.
  • default:"value" — supplies a fallback when the variable is not set.
  • required:"true" — causes Process to return an error if the variable is absent.
  • split_words:"true" — splits a CamelCase field name into UPPER_SNAKE_CASE automatically.
  • ignored:"true" — tells envconfig to skip the field entirely.
type Specification struct {
    ManualOverride1         string `envconfig:"manual_override_1"`
    DefaultVar              string `default:"foobar"`
    RequiredVar             string `required:"true"`
    IgnoredVar              string `ignored:"true"`
    AutoSplitVar            string `split_words:"true"`
}

Examples

Example 1 — Full working program

This program loads all supported basic types from the environment and prints them.

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/kelseyhightower/envconfig"
)

type Specification struct {
    Debug      bool
    Port       int
    User       string
    Users      []string
    Rate       float32
    Timeout    time.Duration
    ColorCodes map[string]int
}

func main() {
    var s Specification
    err := envconfig.Process("myapp", &s)
    if err != nil {
        log.Fatal(err.Error())
    }

    format := "Debug: %v\nPort: %d\nUser: %s\nRate: %f\nTimeout: %s\n"
    _, err = fmt.Printf(format, s.Debug, s.Port, s.User, s.Rate, s.Timeout)
    if err != nil {
        log.Fatal(err.Error())
    }

    fmt.Println("Users:")
    for _, u := range s.Users {
        fmt.Printf("  %s\n", u)
    }

    fmt.Println("Color codes:")
    for k, v := range s.ColorCodes {
        fmt.Printf("  %s: %d\n", k, v)
    }
}

With the environment variables from the quickstart set, running this program produces:

Debug: false
Port: 8080
User: Kelsey
Rate: 0.500000
Timeout: 3m0s
Users:
  rob
  ken
  robert
Color codes:
  red: 1
  green: 2
  blue: 3

Example 2 — Struct tags for defaults and required fields

This example shows how to declare a default value and mark a field as required. If MYAPP_REQUIREDVAR is not set, envconfig.Process returns an error and the program exits.

type Specification struct {
    DefaultVar  string `default:"foobar"`
    RequiredVar string `required:"true"`
}

Set only the required variable and observe the default being used:

export MYAPP_REQUIREDVAR="hello"
go run main.go

DefaultVar will be populated with "foobar" because no environment variable was set for it.


Example 3 — CamelCase splitting with split_words

Without split_words:"true", a field named AutoSplitVar resolves to MYAPP_AUTOSPLITVAR. With the tag, it resolves to MYAPP_AUTO_SPLIT_VAR—which is easier to read and set.

type Specification struct {
    AutoSplitVar string `split_words:"true"`
}
export MYAPP_AUTO_SPLIT_VAR="hello"
go run main.go

Troubleshooting

Issue: envconfig.Process returns an error saying a required variable is missing

  • Symptom: Your program exits immediately with a message like required key MYAPP_REQUIREDVAR missing value.
  • Cause: A struct field is tagged required:"true" and the corresponding environment variable was not set before running the program.
  • Fix: Set the missing variable (export MYAPP_REQUIREDVAR=somevalue) before running the program. If the variable should be optional, remove the required:"true" tag or add a default:"value" tag instead.

Issue: A field stays at its zero value even though the environment variable is set

  • Symptom: For example, Port is 0 even though you ran export MYAPP_PORT=8080.
  • Cause: The environment variable name does not match what envconfig expects. Common causes include: wrong prefix, wrong case, or a CamelCase field name that needs split_words:"true" to resolve correctly.
  • Fix: Double-check the variable name. The default pattern is UPPERCASE_PREFIX + _ + UPPERCASE_FIELDNAME. For a field like ColorCodes with prefix myapp, the variable should be MYAPP_COLORCODES. If you want MYAPP_COLOR_CODES, add split_words:"true" to the field tag.

Issue: A value cannot be converted and Process returns a parse error

  • Symptom: Error message similar to envconfig.Process: assigning MYAPP_PORT to Port: converting 'abc' to type int.
  • Cause: The environment variable contains a value that cannot be converted to the field's Go type (for example, a non-numeric string for an int field).
  • Fix: Correct the value of the environment variable so it matches the expected type. Refer to the supported types list—integers, floats, booleans, time.Duration, slices (comma-separated), and maps (key:value pairs, comma-separated).

Issue: go get fails or the package is not found

  • Symptom: go get github.com/kelseyhightower/envconfig returns a network or module error.
  • Cause: Your project may not be initialized as a Go module, or you may be behind a proxy that blocks the request.
  • Fix: Make sure you have run go mod init <module-name> in your project directory first. If you are behind a corporate proxy, set GOPROXY to an accessible proxy or to direct.

Issue: The ignored:"true" field is still being populated

  • Symptom: A field tagged ignored:"true" appears to receive a value.
  • Cause: Another part of your code may be setting the field directly, or the tag is misspelled.
  • Fix: Verify the tag is exactly ignored:"true" (lowercase, no spaces). envconfig will not attempt to populate the field from the environment, but your own code can still write to it.