Convert Figma logo to code with AI

ilyakaznacheev logocleanenv

✨Clean and minimalistic environment configuration reader for Golang

1,635
113
1,635
44

Top Related Projects

A Go port of Ruby's dotenv library (Loads environment variables from .env files)

26,991

Go configuration with fangs

4,871

A simple, zero-dependencies library to parse environment variables into structs

2,736

Simple, extremely lightweight, extensible, configuration management library for Go. Support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.

Quick Overview

Cleanenv is a Go library for configuration management that combines environment variables, configuration files, and default values. It provides a simple and flexible way to handle application configuration, supporting various formats like YAML, TOML, and JSON.

Pros

  • Easy to use with minimal setup required
  • Supports multiple configuration sources (env vars, files, defaults)
  • Type-safe configuration with automatic parsing and validation
  • Customizable with support for custom parsers and validators

Cons

  • Limited to Go programming language
  • May require additional dependencies for certain file formats (e.g., YAML, TOML)
  • Documentation could be more comprehensive
  • Lacks advanced features like dynamic reloading of configuration

Code Examples

  1. Basic usage with environment variables:
type Config struct {
    Port int `env:"PORT" env-default:"8080"`
    Host string `env:"HOST" env-default:"localhost"`
}

var cfg Config
if err := cleanenv.ReadEnv(&cfg); err != nil {
    log.Fatal(err)
}
  1. Loading configuration from a YAML file:
type Config struct {
    Database struct {
        Host string `yaml:"host" env:"DB_HOST"`
        Port int    `yaml:"port" env:"DB_PORT"`
    } `yaml:"database"`
}

var cfg Config
if err := cleanenv.ReadConfig("config.yml", &cfg); err != nil {
    log.Fatal(err)
}
  1. Using custom tags and validators:
type Config struct {
    APIKey string `env:"API_KEY" env-required:"true"`
    Timeout time.Duration `env:"TIMEOUT" env-default:"30s"`
}

var cfg Config
if err := cleanenv.ReadEnv(&cfg); err != nil {
    log.Fatal(err)
}

Getting Started

To use cleanenv in your Go project:

  1. Install the library:

    go get github.com/ilyakaznacheev/cleanenv
    
  2. Import it in your code:

    import "github.com/ilyakaznacheev/cleanenv"
    
  3. Define your configuration struct with appropriate tags:

    type Config struct {
        Debug bool `env:"DEBUG" env-default:"false"`
        Port  int  `env:"PORT" env-default:"8080"`
    }
    
  4. Read the configuration:

    var cfg Config
    if err := cleanenv.ReadEnv(&cfg); err != nil {
        log.Fatal(err)
    }
    

Now you can use cfg in your application with the loaded configuration values.

Competitor Comparisons

A Go port of Ruby's dotenv library (Loads environment variables from .env files)

Pros of godotenv

  • Simple and straightforward API for loading environment variables
  • Supports loading multiple .env files
  • Widely adopted and well-established in the Go community

Cons of godotenv

  • Limited functionality beyond basic .env file parsing
  • Lacks built-in support for type conversion and validation
  • No direct support for configuration structs or nested configurations

Code Comparison

godotenv:

import "github.com/joho/godotenv"

err := godotenv.Load()
if err != nil {
    log.Fatal("Error loading .env file")
}

cleanenv:

import "github.com/ilyakaznacheev/cleanenv"

type Config struct {
    Port int `env:"PORT" env-default:"8080"`
}

var cfg Config
err := cleanenv.ReadEnv(&cfg)

Key Differences

cleanenv offers a more feature-rich approach to configuration management, including:

  • Automatic parsing of environment variables into structs
  • Built-in type conversion and validation
  • Support for default values and custom tags
  • Integration with various config file formats (YAML, TOML, etc.)

godotenv focuses primarily on loading .env files and provides a simpler, more lightweight solution for basic environment variable management.

Both libraries have their merits, with cleanenv being more suitable for complex configuration needs and godotenv excelling in simplicity for basic use cases.

26,991

Go configuration with fangs

Pros of Viper

  • More feature-rich, supporting multiple configuration formats (JSON, TOML, YAML, etc.)
  • Offers live watching and automatic reloading of configuration files
  • Provides a unified API for accessing configuration from various sources (files, environment variables, flags)

Cons of Viper

  • More complex setup and usage compared to Cleanenv
  • Larger codebase and dependencies, potentially increasing project size
  • May be overkill for simpler projects that don't require all its features

Code Comparison

Cleanenv:

type Config struct {
    Port int `env:"PORT" env-default:"8080"`
}

var cfg Config
err := cleanenv.ReadEnv(&cfg)

Viper:

viper.SetDefault("port", 8080)
viper.AutomaticEnv()
port := viper.GetInt("port")

Summary

Viper offers a more comprehensive solution for configuration management, supporting multiple formats and sources. It's ideal for larger projects with complex configuration needs. Cleanenv, on the other hand, provides a simpler, more straightforward approach, focusing primarily on environment variables and struct tags. It's better suited for smaller projects or those with simpler configuration requirements.

4,871

A simple, zero-dependencies library to parse environment variables into structs

Pros of env

  • Supports more data types, including time.Duration and URL
  • Offers custom parsers for flexible data handling
  • Provides a simpler API with fewer configuration options

Cons of env

  • Lacks support for configuration files (e.g., YAML, JSON)
  • Does not offer built-in validation features
  • Has fewer options for customizing environment variable prefixes

Code Comparison

env:

type Config struct {
    Home   string        `env:"HOME"`
    Port   int           `env:"PORT" envDefault:"3000"`
    Timeout time.Duration `env:"TIMEOUT"`
}

cfg := Config{}
if err := env.Parse(&cfg); err != nil {
    fmt.Printf("%+v\n", err)
}

cleanenv:

type Config struct {
    Home   string        `env:"HOME"`
    Port   int           `env:"PORT" env-default:"3000"`
    Timeout time.Duration `env:"TIMEOUT"`
}

var cfg Config
if err := cleanenv.ReadEnv(&cfg); err != nil {
    fmt.Printf("%+v\n", err)
}

Both libraries offer similar functionality for parsing environment variables into struct fields. The main differences lie in the tag syntax and the parsing function name. env uses envDefault for default values, while cleanenv uses env-default. env uses Parse for parsing, whereas cleanenv uses ReadEnv.

2,736

Simple, extremely lightweight, extensible, configuration management library for Go. Support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.

Pros of koanf

  • Supports multiple configuration sources (files, environment variables, command-line flags)
  • Offers type-safe parsing and unmarshaling into structs
  • Provides a more flexible and extensible architecture

Cons of koanf

  • More complex setup and usage compared to cleanenv
  • Requires more boilerplate code for basic configuration scenarios
  • Steeper learning curve for newcomers

Code Comparison

cleanenv:

type Config struct {
    Port int `env:"PORT" env-default:"8080"`
    Host string `env:"HOST" env-default:"localhost"`
}

var cfg Config
err := cleanenv.ReadEnv(&cfg)

koanf:

var k = koanf.New(".")
k.Load(file.Provider("config.yaml"), yaml.Parser())
k.Load(env.Provider("APP_", ".", func(s string) string {
    return strings.Replace(strings.ToLower(s), "_", ".", -1)
}), nil)

var cfg Config
err := k.Unmarshal("", &cfg)

Both libraries aim to simplify configuration management in Go applications, but koanf offers more flexibility and features at the cost of increased complexity. cleanenv focuses on simplicity and ease of use, making it a good choice for smaller projects or those with straightforward configuration needs.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Clean Env

Clean Env

Minimalistic configuration reader

Mentioned in Awesome Go GoDoc Go Report Card Coverage Status Build Status Release License

Overview

This is a simple configuration reading tool. It just does the following:

  • reads and parses configuration structure from the file
  • reads and overwrites configuration structure from environment variables
  • writes a detailed variable list to help output

Content

Installation

To install the package run

go get -u github.com/ilyakaznacheev/cleanenv

Usage

The package is oriented to be simple in use and explicitness.

The main idea is to use a structured configuration variable instead of any sort of dynamic set of configuration fields like some libraries does, to avoid unnecessary type conversions and move the configuration through the program as a simple structure, not as an object with complex behavior.

There are just several actions you can do with this tool and probably only things you want to do with your config if your application is not too complicated.

  • read configuration file
  • read environment variables
  • read some environment variables again

Read Configuration

You can read a configuration file and environment variables in a single function call.

import "github.com/ilyakaznacheev/cleanenv"

type ConfigDatabase struct {
    Port     string `yaml:"port" env:"PORT" env-default:"5432"`
    Host     string `yaml:"host" env:"HOST" env-default:"localhost"`
    Name     string `yaml:"name" env:"NAME" env-default:"postgres"`
    User     string `yaml:"user" env:"USER" env-default:"user"`
    Password string `yaml:"password" env:"PASSWORD"`
}

var cfg ConfigDatabase

err := cleanenv.ReadConfig("config.yml", &cfg)
if err != nil {
    ...
}

This will do the following:

  1. parse configuration file according to YAML format (yaml tag in this case);
  2. reads environment variables and overwrites values from the file with the values which was found in the environment (env tag);
  3. if no value was found on the first two steps, the field will be filled with the default value (env-default tag) if it is set.

Read Environment Variables Only

Sometimes you don't want to use configuration files at all, or you may want to use .env file format instead. Thus, you can limit yourself with only reading environment variables:

import "github.com/ilyakaznacheev/cleanenv"

type ConfigDatabase struct {
    Port     string `env:"PORT" env-default:"5432"`
    Host     string `env:"HOST" env-default:"localhost"`
    Name     string `env:"NAME" env-default:"postgres"`
    User     string `env:"USER" env-default:"user"`
    Password string `env:"PASSWORD"`
}

var cfg ConfigDatabase

err := cleanenv.ReadEnv(&cfg)
if err != nil {
    ...
}

Update Environment Variables

Some environment variables may change during the application run. To get the new values you need to mark these variables as updatable with the tag env-upd and then run the update function:

import "github.com/ilyakaznacheev/cleanenv"

type ConfigRemote struct {
    Port     string `env:"PORT" env-upd`
    Host     string `env:"HOST" env-upd`
    UserName string `env:"USERNAME"`
}

var cfg ConfigRemote

cleanenv.ReadEnv(&cfg)

// ... some actions in-between

err := cleanenv.UpdateEnv(&cfg)
if err != nil {
    ...
}

Here remote host and port may change in a distributed system architecture. Fields cfg.Port and cfg.Host can be updated in the runtime from corresponding environment variables. You can update them before the remote service call. Field cfg.UserName will not be changed after the initial read, though.

Description

You can get descriptions of all environment variables to use them in the help documentation.

import "github.com/ilyakaznacheev/cleanenv"

type ConfigServer struct {
    Port     string `env:"PORT" env-description:"server port"`
    Host     string `env:"HOST" env-description:"server host"`
}

var cfg ConfigRemote

help, err := cleanenv.GetDescription(&cfg, nil)
if err != nil {
    ...
}

You will get the following:

Environment variables:
  PORT  server port
  HOST  server host

Model Format

Library uses tags to configure the model of configuration structure. There are the following tags:

  • env="<name>" - environment variable name (e.g. env="PORT");
  • env-upd - flag to mark a field as updatable. Run UpdateEnv(&cfg) to refresh updatable variables from environment;
  • env-required - flag to mark a field as required. If set will return an error during environment parsing when the flagged as required field is empty (default Go value). Tag env-default is ignored in this case;
  • env-default="<value>" - default value. If the field wasn't filled from the environment variable default value will be used instead;
  • env-separator="<value>" - custom list and map separator. If not set, the default separator , will be used;
  • env-description="<value>" - environment variable description;
  • env-layout="<value>" - parsing layout (for types like time.Time);
  • env-prefix="<value>" - prefix for all fields of nested structure (only for nested structures);

Supported types

There are following supported types:

  • int (any kind);
  • float (any kind);
  • string;
  • boolean;
  • slices (of any other supported type);
  • maps (of any other supported type);
  • time.Duration;
  • time.Time (layout by default is RFC3339, may be overridden by env-layout);
  • *time.Location (time zone parsing depends on running machine);
  • any type that implements encoding.TextUnmarshaler;
  • any type implementing cleanenv.Setter interface.

Custom Functions

To enhance package abilities you can use some custom functions.

Custom Value Setter

To make custom type allows to set the value from the environment variable, you need to implement the Setter interface on the field level:

type MyField string

func (f *MyField) SetValue(s string) error  {
    if s == "" {
        return fmt.Errorf("field value can't be empty")
    }
    *f = MyField("my field is: "+ s)
    return nil
}

type Config struct {
    Field MyField `env="MY_VALUE"`
}

SetValue method should implement conversion logic from string to custom type.

Custom Value Update

You may need to execute some custom field update logic, e.g. for remote config load.

Thus, you need to implement the Updater interface on the structure level:

type Config struct {
    Field string
}

func (c *Config) Update() error {
    newField, err := SomeCustomUpdate()
    f.Field = newField
    return err
}

Supported File Formats

There are several most popular config file formats supported:

  • YAML (.yaml, .yml)
  • JSON (.json)
  • TOML (.toml)
  • EDN (.edn)
  • ENV (.env)

Note:

  • while using .env file the library will set corresponding data to process environment variables. It will override existing variables with the same keys in the process environment.

Integration

The package can be used with many other solutions. To make it more useful, we made some helpers.

Flag

You can use the cleanenv help together with Golang flag package.

// create some config structure
var cfg config 

// create flag set using `flag` package
fset := flag.NewFlagSet("Example", flag.ContinueOnError)

// get config usage with wrapped flag usage
fset.Usage = cleanenv.FUsage(fset.Output(), &cfg, nil, fset.Usage)

fset.Parse(os.Args[1:])

Examples

type Config struct {
    Port string `yaml:"port" env:"PORT" env-default:"8080"`
    Host string `yaml:"host" env:"HOST" env-default:"localhost"`
}

var cfg Config

err := ReadConfig("config.yml", &cfg)
if err != nil {
    ...
}

This code will try to read and parse the configuration file config.yml as the structure is described in the Config structure. Then it will overwrite fields from available environment variables (PORT, HOST).

For more details check the example directory.

Version Support Policy

We support the last 7 versions of Golang. E.g. if the current version is 1.19, we test compatibility with all versions from 1.19 to 1.13.

If you use an older version of Golang in your project, please use an older library version.

Contribution

The tool is open-sourced under the MIT license.

If you find some error, want to add something or ask a question - feel free to create an issue and/or make a pull request.

Guidelines for contribution may be found in CONTRIBUTING.md.

Any contribution is welcome.

Thanks

Big thanks to a project kelseyhightower/envconfig for inspiration.

The logo was made by alexchoffy.

Blog Posts

Clean Configuration Management in Golang.