projectdiscovery/goflags

A go flag wrapper with convenience helpers

Go

94

410 commits

updated Sep 6, 2026

See the code

README

goflags

License Go version Release Checks

An extension of the go flag library that adds convenience functions and functionalities like config file, better usage, short and long flag support, custom types for string slices and maps etc.

Features

  • YAML configuration with ordered file precedence.
  • Better usage instructions
  • Short and long flags support
  • Custom String Slice types with different options (comma-separated,normalized,etc)
  • Custom Map type
  • Flags grouping support (CreateGroup,SetGroup)

Usage

The following types are supported by the goflags library. The <name>P suffix means that the flag supports both a long and a short flag for the option.

Flag Types

FunctionDescription
BoolVarBoolean value with long name
BoolVarPBoolean value with long short name
DurationVarTime Duration value with long name
DurationVarPTime Duration value with long short name
IntVarInteger value with long name
IntVarPInteger value with long short name
PortVarPort value with long name
PortVarPPort value with long short name
RuntimeMapVarMap value with long name
RuntimeMapVarPMap value with long short name
StringSliceVarString Slice value with long name and options
StringSliceVarConfigOnlyString Slice value with long name read from config file only
StringSliceVarPString slice value with long short name and options
StringVarString value with long name
StringVarEnvString value with long short name read from environment
StringVarPString value with long short name
VarCustom value with long name implementing flag.Value interface
VarPCustom value with long short name implementing flag.Value interface
EnumVarEnum value with long name
EnumVarPEnum value with long short name
AuthVarAuth token with long name (supports interactive prompt and env var)
AuthVarPAuth token with long short name
CallbackVarCallback function as value with long name
CallbackVarPCallback function as value with long short name
SizeVarString value with long name
SizeVarPString value with long short name

String Slice Options

String Slice OptionTokenizationNormalizationDescription
StringSliceOptionsNoneNoneDefault String Slice
CommaSeparatedStringSliceOptionsCommaNoneComma-separated string slice
FileCommaSeparatedStringSliceOptionsCommaNoneComma-separated items from file/cli
NormalizedOriginalStringSliceOptionsNoneStandardList of normalized string slice
FileNormalizedStringSliceOptionsCommaStandardList of normalized string slice from file/cli
FileStringSliceOptionsStandardStandardList of string slice from file
NormalizedStringSliceOptionsCommaStandardList of normalized string slice

Cascading Configuration

Use SetConfigFilePaths to load more than one YAML configuration file. List the files from lowest to highest priority. For example, you can load system-wide configuration first and let the user's configuration override it:

userConfigFile, err := flagSet.GetConfigFilePath()
if err != nil {
	log.Fatal(err)
}

flagSet.SetConfigFilePaths("/etc/example/config.yaml", userConfigFile)
if err := flagSet.Parse(); err != nil {
	log.Fatal(err)
}

The following precedence rules apply:

  • Command-line flags override all configuration files.
  • A value in a later file overrides the value from an earlier file.
  • If a later file does not contain an option, the earlier value remains in use.

The last path is the primary user configuration file. Parse creates this file if it does not exist. Missing lower-priority files are skipped, but other file errors are returned. Earlier files are always read-only.

Parse and MergeConfigFile return configuration errors (malformed YAML, unsupported or invalid values). A failure while applying cascaded files rolls back every assignment from that apply, including values from lower-priority files, so compiled defaults remain. Sequential MergeConfigFile calls roll back only the failed file.

Built-in collection types replace the complete collection instead of merging items. Custom flag.Value implementations keep their own Set behavior. Callback flags are CLI-only, so configuration files cannot run them.

Example

An example showing various options of the library is specified below.

package main

import (
	"fmt"
	"log"

	"github.com/projectdiscovery/goflags"
)

type options struct {
	silent bool
	inputs goflags.StringSlice
	config string
	values goflags.RuntimeMap
}

const (
	Nil goflags.EnumVariable = iota
	Type1
	Type2
)

func main() {
	enumAllowedTypes := goflags.AllowdTypes{"type1": Type1, "type2": Type2}
	opt := &options{}

	flagSet := goflags.NewFlagSet()
	flagSet.SetDescription("Test program to demonstrate goflags options")

	flagSet.EnumVarP(&options.Type, "enum-type", "et", Nil, "Variable Type (type1/type2)", enumAllowedTypes)
	flagSet.BoolVar(&opt.silent, "silent", true, "show silent output")
	flagSet.StringSliceVarP(&opt.inputs, "inputs", "i", nil, "list of inputs (file,comma-separated)", goflags.FileCommaSeparatedStringSliceOptions)

	update := func(tool string ) func() { 
		return func()  {
			fmt.Printf("%v updated successfully!", tool)
		}
	}
	flagSet.CallbackVarP(update("tool_1"), "update", "up", "update tool_1")


	// Group example
	flagSet.CreateGroup("config", "Configuration",
		flagSet.StringVar(&opt.config, "config", "", "file to read config from"),
		flagSet.RuntimeMapVar(&opt.values, "values", nil, "key-value runtime values"),
	)
	if err := flagSet.Parse(); err != nil {
		log.Fatalf("Could not parse flags: %s\n", err)
	}
	if opt.config != "" {
		if err := flagSet.MergeConfigFile(opt.config); err != nil {
			log.Fatalf("Could not merge config file: %s\n", err)
		}
	}
	fmt.Printf("silent: %v inputs: %v config: %v values: %v\n", opt.silent, opt.inputs, opt.config, opt.values)
}

Thanks

  1. spf13/cobra - For the very nice usage template for the command line.
  2. nmap/nmap - For the service-port mapping and top-ports list.
goflags
hacktoberfest
library

projectdiscovery/goflags

A go flag wrapper with convenience helpers

Go

94

410 commits

updated Sep 6, 2026

See the code

README

goflags

License Go version Release Checks

An extension of the go flag library that adds convenience functions and functionalities like config file, better usage, short and long flag support, custom types for string slices and maps etc.

Features

  • YAML configuration with ordered file precedence.
  • Better usage instructions
  • Short and long flags support
  • Custom String Slice types with different options (comma-separated,normalized,etc)
  • Custom Map type
  • Flags grouping support (CreateGroup,SetGroup)

Usage

The following types are supported by the goflags library. The <name>P suffix means that the flag supports both a long and a short flag for the option.

Flag Types

FunctionDescription
BoolVarBoolean value with long name
BoolVarPBoolean value with long short name
DurationVarTime Duration value with long name
DurationVarPTime Duration value with long short name
IntVarInteger value with long name
IntVarPInteger value with long short name
PortVarPort value with long name
PortVarPPort value with long short name
RuntimeMapVarMap value with long name
RuntimeMapVarPMap value with long short name
StringSliceVarString Slice value with long name and options
StringSliceVarConfigOnlyString Slice value with long name read from config file only
StringSliceVarPString slice value with long short name and options
StringVarString value with long name
StringVarEnvString value with long short name read from environment
StringVarPString value with long short name
VarCustom value with long name implementing flag.Value interface
VarPCustom value with long short name implementing flag.Value interface
EnumVarEnum value with long name
EnumVarPEnum value with long short name
AuthVarAuth token with long name (supports interactive prompt and env var)
AuthVarPAuth token with long short name
CallbackVarCallback function as value with long name
CallbackVarPCallback function as value with long short name
SizeVarString value with long name
SizeVarPString value with long short name

String Slice Options

String Slice OptionTokenizationNormalizationDescription
StringSliceOptionsNoneNoneDefault String Slice
CommaSeparatedStringSliceOptionsCommaNoneComma-separated string slice
FileCommaSeparatedStringSliceOptionsCommaNoneComma-separated items from file/cli
NormalizedOriginalStringSliceOptionsNoneStandardList of normalized string slice
FileNormalizedStringSliceOptionsCommaStandardList of normalized string slice from file/cli
FileStringSliceOptionsStandardStandardList of string slice from file
NormalizedStringSliceOptionsCommaStandardList of normalized string slice

Cascading Configuration

Use SetConfigFilePaths to load more than one YAML configuration file. List the files from lowest to highest priority. For example, you can load system-wide configuration first and let the user's configuration override it:

userConfigFile, err := flagSet.GetConfigFilePath()
if err != nil {
	log.Fatal(err)
}

flagSet.SetConfigFilePaths("/etc/example/config.yaml", userConfigFile)
if err := flagSet.Parse(); err != nil {
	log.Fatal(err)
}

The following precedence rules apply:

  • Command-line flags override all configuration files.
  • A value in a later file overrides the value from an earlier file.
  • If a later file does not contain an option, the earlier value remains in use.

The last path is the primary user configuration file. Parse creates this file if it does not exist. Missing lower-priority files are skipped, but other file errors are returned. Earlier files are always read-only.

Parse and MergeConfigFile return configuration errors (malformed YAML, unsupported or invalid values). A failure while applying cascaded files rolls back every assignment from that apply, including values from lower-priority files, so compiled defaults remain. Sequential MergeConfigFile calls roll back only the failed file.

Built-in collection types replace the complete collection instead of merging items. Custom flag.Value implementations keep their own Set behavior. Callback flags are CLI-only, so configuration files cannot run them.

Example

An example showing various options of the library is specified below.

package main

import (
	"fmt"
	"log"

	"github.com/projectdiscovery/goflags"
)

type options struct {
	silent bool
	inputs goflags.StringSlice
	config string
	values goflags.RuntimeMap
}

const (
	Nil goflags.EnumVariable = iota
	Type1
	Type2
)

func main() {
	enumAllowedTypes := goflags.AllowdTypes{"type1": Type1, "type2": Type2}
	opt := &options{}

	flagSet := goflags.NewFlagSet()
	flagSet.SetDescription("Test program to demonstrate goflags options")

	flagSet.EnumVarP(&options.Type, "enum-type", "et", Nil, "Variable Type (type1/type2)", enumAllowedTypes)
	flagSet.BoolVar(&opt.silent, "silent", true, "show silent output")
	flagSet.StringSliceVarP(&opt.inputs, "inputs", "i", nil, "list of inputs (file,comma-separated)", goflags.FileCommaSeparatedStringSliceOptions)

	update := func(tool string ) func() { 
		return func()  {
			fmt.Printf("%v updated successfully!", tool)
		}
	}
	flagSet.CallbackVarP(update("tool_1"), "update", "up", "update tool_1")


	// Group example
	flagSet.CreateGroup("config", "Configuration",
		flagSet.StringVar(&opt.config, "config", "", "file to read config from"),
		flagSet.RuntimeMapVar(&opt.values, "values", nil, "key-value runtime values"),
	)
	if err := flagSet.Parse(); err != nil {
		log.Fatalf("Could not parse flags: %s\n", err)
	}
	if opt.config != "" {
		if err := flagSet.MergeConfigFile(opt.config); err != nil {
			log.Fatalf("Could not merge config file: %s\n", err)
		}
	}
	fmt.Printf("silent: %v inputs: %v config: %v values: %v\n", opt.silent, opt.inputs, opt.config, opt.values)
}

Thanks

  1. spf13/cobra - For the very nice usage template for the command line.
  2. nmap/nmap - For the service-port mapping and top-ports list.
goflags
hacktoberfest
library

Significant stargazers

BinBin He

213 followers · starred Dec 2023