env

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2025 License: Apache-2.0 Imports: 7 Imported by: 0

README ΒΆ

go-env (with prefix support)

Build Status Go Reference NetflixOSS Lifecycle

Note: This is a fork of Netflix's go-env with additional support for prefix directives in struct tags. Package env provides an env struct field tag to marshal and unmarshal environment variables.

Usage

package main

import (
 "log"
 "time"

 "github.com/dimahluodba96/go-env"
)

type Environment struct {
 Home string `env:"HOME"`

 Jenkins struct {
  BuildId     *string `env:"BUILD_ID"`
  BuildNumber int     `env:"BUILD_NUMBER"`
  Ci          bool    `env:"CI"`
 }

 Node struct {
  ConfigCache *string `env:"npm_config_cache,NPM_CONFIG_CACHE"`
 }

 Extras env.EnvSet

 Duration      time.Duration `env:"TYPE_DURATION"`
 DefaultValue  string        `env:"MISSING_VAR,default=default_value"`
 RequiredValue string        `env:"IM_REQUIRED,required=true"`
 ArrayValue    []string      `env:"ARRAY_VALUE,default=value1|value2|value3"`
}

func main() {
 var environment Environment
 es, err := env.UnmarshalFromEnviron(&environment)
 if err != nil {
  log.Fatal(err)
 }
 // Remaining environment variables.
 environment.Extras = es

 // ...

 es, err = env.Marshal(&environment)
 if err != nil {
  log.Fatal(err)
 }

 home := "/tmp/edgarl"
 cs := env.ChangeSet{
  "HOME":         &home,
  "BUILD_ID":     nil,
  "BUILD_NUMBER": nil,
 }
 es.Apply(cs)

 environment = Environment{}
 if err = env.Unmarshal(es, &environment); err != nil {
  log.Fatal(err)
 }

 environment.Extras = es
}

πŸ†• Prefix Support

This fork adds support for prefix directives that automatically prepend prefixes to environment variable names for nested structs. This is particularly useful for grouping related configuration settings.

Basic Prefix Usage
package main

import (
 "log"
 "os"

 "github.com/dimahluodba96/go-env"
)

// Config holds all configuration for our application
type Config struct {
 Server   ServerConfig   `env:"prefix=SERVER_"`
 Database DatabaseConfig `env:"prefix=DATABASE_"`
 JWT      JWTConfig      // No prefix - uses env var names as-is
}

// ServerConfig holds server configuration
type ServerConfig struct {
 Host string `env:"HOST,default=localhost"`     // Reads SERVER_HOST
 Port string `env:"PORT,default=8080"`          // Reads SERVER_PORT
 Mode string `env:"MODE,default=debug"`         // Reads SERVER_MODE
}

// DatabaseConfig holds database configuration
type DatabaseConfig struct {
 Host     string `env:"HOST,default=localhost"`     // Reads DATABASE_HOST
 Port     string `env:"PORT,default=5432"`          // Reads DATABASE_PORT
 Username string `env:"USERNAME,default=postgres"`  // Reads DATABASE_USERNAME
 Password string `env:"PASSWORD"`                   // Reads DATABASE_PASSWORD
 Database string `env:"DATABASE,default=myapp"`     // Reads DATABASE_DATABASE
}

// JWTConfig holds JWT configuration (no prefix)
type JWTConfig struct {
 Secret     string `env:"JWT_SECRET"`                    // Reads JWT_SECRET
 ExpiryTime string `env:"JWT_EXPIRY,default=24h"`        // Reads JWT_EXPIRY
}

func main() {
 // Set some environment variables for demonstration
 os.Setenv("SERVER_HOST", "api.example.com")
 os.Setenv("SERVER_PORT", "3000")
 os.Setenv("DATABASE_HOST", "db.example.com")
 os.Setenv("DATABASE_USERNAME", "admin")
 os.Setenv("DATABASE_PASSWORD", "secret123")
 os.Setenv("JWT_SECRET", "super-secret-key")

 var config Config
 _, err := env.UnmarshalFromEnviron(&config)
 if err != nil {
  log.Fatal(err)
 }

 // config.Server.Host = "api.example.com" (from SERVER_HOST)
 // config.Server.Port = "3000" (from SERVER_PORT)
 // config.Server.Mode = "debug" (default, SERVER_MODE not set)
 // config.Database.Host = "db.example.com" (from DATABASE_HOST)
 // config.JWT.Secret = "super-secret-key" (from JWT_SECRET)
}
Nested Prefixes

Prefixes can be nested and will accumulate:

type Root struct {
 Level1 Level1Config `env:"prefix=LEVEL1_"`
}

type Level1Config struct {
 Nested Level2Config `env:"prefix=LEVEL2_"`
 Direct string       `env:"DIRECT"`  // Reads LEVEL1_DIRECT
}

type Level2Config struct {
 Value string `env:"VALUE"`  // Reads LEVEL1_LEVEL2_VALUE
}
Key Features
  • Automatic Prefixing: Environment variables are automatically prefixed for nested structs
  • Backward Compatible: All existing functionality works exactly as before
  • Flexible: Mix prefixed and non-prefixed structs in the same configuration
  • Nested Support: Prefixes accumulate for deeply nested structures
  • Marshal Support: Prefixes work with both unmarshaling and marshaling

This will initially throw an error if IM_REQUIRED is not set in the environment as part of the env struct validation.This error can be resolved by setting the IM_REQUIRED environment variable manually in the environment or by setting it in the code prior to calling UnmarshalFromEnviron with:

os.Setenv("IM_REQUIRED", "some_value")

Custom Marshaler/Unmarshaler

There is limited support for dictating how a field should be marshaled or unmarshaled. The following example shows how you could marshal/unmarshal from JSON

package main

import (
 "encoding/json"
 "fmt"
 "log"

 "github.com/dimahluodba96/go-env"
)

type SomeData struct {
    SomeField int `json:"someField"`
}

func (s *SomeData) UnmarshalEnvironmentValue(data string) error {
    var tmp SomeData
 if  err := json.Unmarshal([]byte(data), &tmp); err != nil {
  return err
 }
 *s = tmp
 return nil
}

func (s SomeData) MarshalEnvironmentValue() (string, error) {
 bytes, err := json.Marshal(s)
 if err != nil {
  return "", err
 }
 return string(bytes), nil
}

type Config struct {
    SomeData *SomeData `env:"SOME_DATA"`
}

func main() {
 var cfg Config
 if _, err := env.UnmarshalFromEnviron(&cfg); err != nil {
  log.Fatal(err)
 }

    if cfg.SomeData != nil && cfg.SomeData.SomeField == 42 {
        fmt.Println("Got 42!")
    } else {
        fmt.Printf("Got nil or some other value: %v\n", cfg.SomeData)
    }

    es, err := env.Marshal(&cfg)
 if err != nil {
  log.Fatal(err)
 }
    fmt.Printf("Got the following: %+v\n", es)
}

Changes from Original

This fork adds the following enhancements to the original Netflix go-env library:

✨ New Features
  • Prefix Support: Use prefix=VALUE in struct tags to automatically prepend prefixes to environment variable names
  • Nested Prefixes: Prefixes accumulate for deeply nested structures
  • Marshal Support: Prefixes work in both directions (unmarshal and marshal)
πŸ”§ Improvements
  • Fixed Deletion Logic: Environment variables are now properly deleted from EnvSet after processing
  • Enhanced Tests: Added comprehensive test coverage for prefix functionality
πŸ“ Attribution

Original work by Netflix, Inc. under Apache License 2.0. Prefix functionality added by @dimahluodba96.


License: Apache License 2.0

Documentation ΒΆ

Overview ΒΆ

Package env provides an `env` struct field tag to marshal and unmarshal environment variables.

Copyright 2018 Netflix, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var (
	// ErrInvalidValue returned when the value passed to Unmarshal is nil or not a
	// pointer to a struct.
	ErrInvalidValue = errors.New("value must be a non-nil pointer to a struct")

	// ErrUnsupportedType returned when a field with tag "env" is unsupported.
	ErrUnsupportedType = errors.New("field is an unsupported type")

	// ErrUnexportedField returned when a field with tag "env" is not exported.
	ErrUnexportedField = errors.New("field must be exported")
)
View Source
var ErrInvalidEnviron = errors.New("items in environ must have format key=value")

ErrInvalidEnviron returned when environ has an incorrect format.

Functions ΒΆ

func EnvSetToEnviron ΒΆ

func EnvSetToEnviron(m EnvSet) []string

EnvSetToEnviron transforms a EnvSet into a slice of strings with the format "key=value".

func Unmarshal ΒΆ

func Unmarshal(es EnvSet, v interface{}) error

Unmarshal parses an EnvSet and stores the result in the value pointed to by v. Fields that are matched in v will be deleted from EnvSet, resulting in an EnvSet with the remaining environment variables. If v is nil or not a pointer to a struct, Unmarshal returns an ErrInvalidValue.

Fields tagged with "env" will have the unmarshalled EnvSet of the matching key from EnvSet. If the tagged field is not exported, Unmarshal returns ErrUnexportedField.

If the field has a type that is unsupported, Unmarshal returns ErrUnsupportedType.

Types ΒΆ

type ChangeSet ΒΆ

type ChangeSet map[string]*string

ChangeSet represents a set of environment variables changes, corresponding to os.Setenv and os.Unsetenv operations.

type EnvSet ΒΆ

type EnvSet map[string]string

EnvSet represents a set of environment variables.

func EnvironToEnvSet ΒΆ

func EnvironToEnvSet(environ []string) (EnvSet, error)

EnvironToEnvSet transforms a slice of string with the format "key=value" into the corresponding EnvSet. If any item in environ does follow the format, EnvironToEnvSet returns ErrInvalidEnviron.

func Marshal ΒΆ

func Marshal(v interface{}) (EnvSet, error)

Marshal returns an EnvSet of v. If v is nil or not a pointer, Marshal returns an ErrInvalidValue.

Marshal uses fmt.Sprintf to transform encountered values to its default string format. Values without the "env" field tag are ignored.

Nested structs are traversed recursively.

func UnmarshalFromEnviron ΒΆ

func UnmarshalFromEnviron(v interface{}) (EnvSet, error)

UnmarshalFromEnviron parses an EnvSet from os.Environ and stores the result in the value pointed to by v. Fields that weren't matched in v are returned in an EnvSet with the remaining environment variables. If v is nil or not a pointer to a struct, UnmarshalFromEnviron returns an ErrInvalidValue.

Fields tagged with "env" will have the unmarshalled EnvSet of the matching key from EnvSet. If the tagged field is not exported, UnmarshalFromEnviron returns ErrUnexportedField.

If the field has a type that is unsupported, UnmarshalFromEnviron returns ErrUnsupportedType.

func (EnvSet) Apply ΒΆ

func (e EnvSet) Apply(cs ChangeSet)

Apply applies a ChangeSet to EnvSet, modifying its contents.

type ErrMissingRequiredValue ΒΆ

type ErrMissingRequiredValue struct {
	// Value is the type of value that is required to provide error context to
	// the caller
	Value string
}

ErrMissingRequiredValue returned when a field with required=true contains no value or default

func (ErrMissingRequiredValue) Error ΒΆ

func (e ErrMissingRequiredValue) Error() string

type Marshaler ΒΆ

type Marshaler interface {
	MarshalEnvironmentValue() (string, error)
}

Marshaler is the interface implemented by types that can marshal themselves into valid environment variable values.

type Unmarshaler ΒΆ

type Unmarshaler interface {
	UnmarshalEnvironmentValue(data string) error
}

Unmarshaler is the interface implemented by types that can unmarshal an environment variable value representation of themselves. The input can be assumed to be the raw string value stored in the environment.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL