Loading configuration

  1. Parse — allocate and decode
  2. Load — decode into an existing value
  3. Unmarshal — decode raw bytes
  4. LoadContext / ParseContext — thread a context
  5. Low-level API

oneenv gives you a small, layered API. Pick the entry point that fits.

Parse — allocate and decode

Parse[T] is the generic convenience form: it allocates a T, decodes into it, and returns the pointer.

cfg, err := oneenv.Parse[Config]()                       // reads the default ".env"

// Point it at one or more files — later files override earlier keys:
cfg, err := oneenv.Parse[Config](
    oneenv.WithFiles(".env", ".env.local", ".env.production"),
)

Load — decode into an existing value

var cfg Config
err := oneenv.Load(&cfg, oneenv.WithFiles(".env", ".env.local"))

v must be a non-nil pointer to a struct. Both Parse and Load are safe for concurrent use.

Unmarshal — decode raw bytes

Decodes .env-formatted bytes directly, without touching any file or the process environment. Handy for embedded configs or tests.

data := []byte("PORT=9090\nHOST=localhost")
var cfg Config
err := oneenv.Unmarshal(data, &cfg)

LoadContext / ParseContext — thread a context

Use these when you register mutators that need a context.Context.

cfg, err := oneenv.ParseContext[Config](ctx, oneenv.WithMutator(resolveSecret))

Low-level API

When you only need the raw values, not a struct:

vals, _ := oneenv.Read(".env", ".env.local")   // merge files → map[string]string
_ = oneenv.LoadEnv(".env", ".env.local")        // sets os.Setenv (existing wins)
_ = oneenv.Overload(".env", ".env.local")       // sets os.Setenv (.env wins)

Read, LoadEnv and Overload are variadic — pass as many .env files as you like; later files override earlier keys. With no arguments they default to .env.