dotenv

module
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT

README

dotenv: Parse .env files for Go

Go Report Card GoDoc Tests

Dotenv files, typically named .env, store configuration settings as key-value pairs. This format originates from shell scripts used to set environment variables.

Installation

To use dotenv in your Go project, install it with:

go get github.com/ctx42/dotenv

Usage

The library offers a single function, Parse, which reads dotenv-formatted content from a reader and stores it in a key-value map.

func Parse(m map[string]string, r io.Reader) error
Basic
file := `
HELLO="hello"
WORLD=world
`

m := map[string]string{}
r := strings.NewReader(file)

if err := dotenv.Parse(m, r); err != nil {
    panic(err)
}

fmt.Println(dump.Any(m))
// Output:
// map[string]string{
//   "HELLO": "hello",
//   "WORLD": "world",
// }

You can prefix lines with "export" to enable sourcing the file in a shell environment:

export KEY_ONE=value_one
export KEY_TWO=value_two

For cross-system compatibility, key names should use letters, numbers, and underscores only and must not start with a number. This follows the regular expression:

[a-zA-Z_]+[a-zA-Z0-9_]*
FOOBAR   # ok
FOO_BAR  # ok
foobar   # ok
foo_bar  # ok
foo-bar  # invalid
∑KEY     # invalid
123VAR   # invalid

Values follow the equals sign and can be enclosed in quotes if needed. Single quotes prevent variable expansion within the value.

SIMPLE=hello
EXPAND="multiple\nlines text with variable expansion: ${SIMPLE}"
DO_NOT_EXPAND='raw text without variable interpolation'
Comments

Lines starting with # are treated as comments. Comments can also appear after a value if separated by a space but only outside quotes. Within quoted strings, # is treated as a regular character.

file := `
# Comment.
QUOTED="a # b # c #"
AFTER_SPACE=world # Comment.
`

m := map[string]string{}
r := strings.NewReader(file)

if err := dotenv.Parse(m, r); err != nil {
    panic(err)
}

fmt.Println(dump.Any(m))
// Output:
// map[string]string{
//   "AFTER_SPACE": "world",
//   "QUOTED": "a # b # c #",
// }
Variable Expansion

Unquoted or double-quoted values support placeholders like ${VAR_NAME}, which are replaced with the values of previously defined variables in the file. Environment variables are not expanded.

For instance:

file := `
HELLO=hello
WORLD=world
MESSAGE="${HELLO} ${WORLD}!"
`

m := map[string]string{}
r := strings.NewReader(file)

if err := dotenv.Parse(m, r); err != nil {
    panic(err)
}

fmt.Println(m["MESSAGE"])
// Output:
// hello world!

To expand environment variables, provide an initialized map with the keys to expand.

file := `
HELLO=hello
WORLD=world
MESSAGE="${HELLO} ${WORLD}${EXCLAIM}"
`

env := map[string]string{
    "HELLO":   "env-hello",
    "EXCLAIM": "!",
}
r := strings.NewReader(file)

if err := dotenv.Parse(env, r); err != nil {
    panic(err)
}

fmt.Println(dump.Any(env))
// Output:
// map[string]string{
//   "EXCLAIM": "!",
//   "HELLO": "hello",
//   "MESSAGE": "hello world!",
//   "WORLD": "world",
// }

Note that keys from the reader overwrite keys in the initialized map.

Split

Split converts the output of os.Environ() into a map suitable for pre-seeding Parse with existing environment variables.

// Convert os.Environ() output into a map suitable for
// pre-seeding Parse with existing environment variables.
env := dotenv.Split([]string{
    "HOME=/home/user",
    "PATH=/usr/local/bin:/usr/bin",
    "USER=alice",
})

fmt.Println(dump.Any(env))
// Output:
// map[string]string{
//   "HOME": "/home/user",
//   "PATH": "/usr/local/bin:/usr/bin",
//   "USER": "alice",
// }
Preventing Expansion

To preserve placeholders like ${} in a value, enclose it in single quotes:

file := `
HELLO=hello
WORLD=world
MESSAGE='${HELLO} ${WORLD}!'
`

m := map[string]string{}
r := strings.NewReader(file)

if err := dotenv.Parse(m, r); err != nil {
    panic(err)
}

fmt.Println(m["MESSAGE"])
// Output:
// ${HELLO} ${WORLD}!
Escape Characters

Certain backslash sequences are replaced with special characters during parsing, similar to shell script behavior. Files are read as UTF-8, converting specific byte pairs into single characters:

  • \n - becomes a newline (line feed)
  • \r - becomes a carriage return
  • \t - becomes a tab
  • \f - becomes a form feed
  • \b - becomes a backspace
  • \" - becomes a double quote
  • \' - becomes a single quote
  • \\ - becomes a backslash
  • \uABCD inserts a Unicode character (four hex digits)

If a backslash precedes any other character, the backslash is removed, and the character is retained as is.

Disclaimer

The parsing internals — regex patterns, comment stripping, quote handling, and variable expansion — are derived from godotenv. The public API is an independent design that differs in several key ways:

  • Single entry point. godotenv exposes many functions (Load, Overload, Read, Write, Marshal, Unmarshal, Env, Exec). This library provides one: Parse.
  • io.Reader interface. godotenv accepts file paths. Parse accepts any io.Reader, keeping I/O concerns with the caller and making the parser straightforward to test.
  • Caller-owned map. The caller passes in the destination map. This makes the output container explicit, avoids hidden allocations, and enables the pre-seeding pattern below.
  • Explicit environment variable expansion. godotenv expands OS environment variables automatically. Here, expansion is opt-in: pre-seed the map with Split(os.Environ()) before calling Parse.
  • No OS side effects. godotenv's Load calls os.Setenv. Parse never touches the OS environment.

Directories

Path Synopsis
pkg
dotenv
Package dotenv parses .env format configuration files.
Package dotenv parses .env format configuration files.

Jump to

Keyboard shortcuts

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