Loading values from the environment into variables is a way to configure processes at startup. Alternatives are to define a command-line interface or parsing configuration files.

Each of these methods has its advantage but loading values from the environment has a shortcoming. As an operator you have to refer to the documentation of the tool as there is no interface to query what the process expects.

This is possible when using a command line interface as libraries have implemented a default -h/--help flag that will print what is expected. It is also possible to use a format for configuration files that supports comments to document the values supported.

I have published another environment variable parser package that fills this void as follows.

  1. It is possible to define program variables that will hold the associated environment values.
  2. It is possible to define different sets of environment variables in the same application. This allows subcommands to have their own environment variables.
  3. It is possible to get a description of the set of environment variables that includes the name, type, default value, and a short description.

I have adapted the flag package for this purpose and it is available here. I would like to thank the Go authors for the flag package’s design. It was fairly easy to adapt it and all the errors you may find are my own.

This is a minimal example to see how the package can be used to load values from the environment in program variables and get a description of the variables the program expects.

package main

import (
  "github.com/edoput/env"
)

func main() {
  var _ = env.Bool("BLEP", false, "Should we blep?") // do gophers blep?
  env.Parse()
}

And the corresponding usage as an operator.

$ main # no output
$ HELP= main # setting HELP or H will trigger the usage message
Environment of main:
  BLEP  boolean
    	Should we blep?

Is this good? Is this bad? I’m not sure but I’m not going back.

Previous art in environment loading

There are many packages dedicated to parsing values from environment variables. Here is an incomplete list along with their pros.

Most of these packages focus on loading environment variables into one config structure as a program variable. All provide a procedural API and almost all support some sort of reflection driven by struct tags. One of these packages introspect on the environment variables the program declares to do something meaningful.

  • kelseyhightowers/envconfig

    Package envconfig implements decoding of environment variables based on a user defined specification.

    This package is by far the most popular I can find. It supports loading values into a structure, struct tags to make that easy, and custom decoders. There are many other reimplementations but none has the same reach.

  • olivere/env

    The env package is to simplify reading environment variables with e.g. the flag package.

    This package actually implements a similar API but focuses on using environment variables as fallbacks for flag variables.

  • code.cloudfoundry.org/go-envstruct

    envstruct is a simple library for populating values on structs from environment variables.

    This package is the first that implements the missing feature. The WriteReport function can be used to give a description of the environment variables the program defines but is not wired up by default.