Skip to content
Flags-first package for configuration
Branch: master
Clone or download

ff Latest Release GoDoc status

ff stands for flags-first, and provides an opinionated way to populate a flag.FlagSet with configuration data from the environment. By default, it parses only from the command line, but you can enable parsing from a configuration file and/or environmental variables.

With everything enabled, the priority order is:

  1. Command line flags (highest priority)
  2. Configuration file
  3. Environment variables (lowest priority)


Define a flag.FlagSet in your func main.

func main() {
	fs := flag.NewFlagSet("my-program", flag.ExitOnError)
	var (
		listenAddr = fs.String("listen-addr", "localhost:8080", "listen address")
		refresh    = fs.Duration("refresh", 15*time.Second, "refresh interval")
		debug      = fs.Bool("debug", false, "log debug information")
		_          = fs.String("config", "", "config file (optional)")

Then, call ff.Parse instead of fs.Parse.

	ff.Parse(fs, os.Args[1:],

This example will parse flags from the commandline args, just like regular package flag, with the highest priority. If a -config file is specified, it will try to parse it using the PlainParser, which expects files in this format.

listen-addr localhost:8080
refresh 30s
debug true

You could also use the JSONParser, which expects a JSON object.

	"listen-addr": "localhost:8080",
	"refresh": "30s",
	"debug": true

Or, you could write your own config file parser.

// ConfigFileParser interprets the config file represented by the reader
// and calls the set function for each parsed flag pair.
type ConfigFileParser func(r io.Reader, set func(name, value string) error) error

Finally, it will look in the environment for variables with a MY_PROGRAM prefix. Flag names are capitalized, and separator characters are converted to underscores. In this case, for example, MY_PROGRAM_LISTEN_ADDR would match to listen-addr.

You can’t perform that action at this time.