User Guide

kotlin-dotenv-parser parses dotenv text into ordered entries. It is a parser, not a process-wide environment mutator.

Basic Parsing

import one.wabbit.dotenv.parser.parseDotenvText

val entries =
    parseDotenvText(
        """
        APP_ENV=production
        PORT=8080
        PASSWORD='pa#ss with spaces'
        """.trimIndent()
    )

val env = entries.associate { it.key to it.value }

The parser ignores blank lines and full-line comments. Each assignment must contain =.

Keys

Keys may contain letters, digits, underscores, dots, and dashes. An optional export prefix is accepted and ignored:

export APP_ENV=production
SERVICE.NAME=api
SERVICE-VERSION=2026.05

If you need stricter shell-style names for braced variable expansion, set DotenvParseOptions(strictNames = true). This affects ${...} expansion names, not assignment key parsing.

Values

Values may be unquoted, single-quoted, or double-quoted.

A=plain
B='literal value with # and spaces'
C="double quoted\nwith escapes"

Single-quoted values are literal and can span lines. Double-quoted values can also span lines and support escapes for newline, carriage return, tab, quote, backslash, and dollar. Unquoted values are trimmed and support escapes for whitespace, dollar, hash, newline, carriage return, and tab.

Trailing comments start with # only after whitespace:

A=1 # comment
B=2#hash-is-part-of-value

Variable Expansion

Variable expansion is opt-in:

import one.wabbit.dotenv.parser.DotenvParseOptions
import one.wabbit.dotenv.parser.parseDotenvText

val entries =
    parseDotenvText(
        """
        HOST=example.test
        URL=https://${'$'}{HOST}/api
        DEFAULTED=${'$'}{MISSING:-fallback}
        """.trimIndent(),
        DotenvParseOptions(expandVariables = true)
    )

Supported forms include $NAME, ${NAME}, ${NAME:-word}, ${NAME-word}, ${NAME:+word}, ${NAME+word}, ${NAME:=word}, ${NAME=word}, ${NAME:?message}, and ${NAME?message}.

The colon variants treat empty strings like unset values. The non-colon variants only treat missing variables as unset.

Expansion is ordered. Earlier parsed entries and initialEnv are visible to later entries. Later assignments do not retroactively change already parsed values.

Command Substitution

Command substitution is opt-in and should only be enabled for trusted dotenv input:

import one.wabbit.dotenv.parser.DotenvParseOptions
import one.wabbit.dotenv.parser.parseDotenvText

val entries =
    parseDotenvText(
        "USER=$(whoami)",
        DotenvParseOptions(commandSubstitution = true)
    )

The JVM implementation executes commands through a shell. Android and native implementations report command substitution as unsupported.

The parser applies these safeguards by default:

  • commands do not inherit the parent process environment
  • stdout is capped at 1 MiB
  • each command has a 10 second timeout
  • each value may contain at most five command substitutions
  • non-zero exits fail parsing
  • backtick substitutions are rejected

Use DotenvParseOptions to tune those limits when you intentionally need different behavior.

Errors

All parser errors extend DotenvParseException. The exception carries the one-based line number, optional column, and source context used to render the diagnostic.

Catch specific subclasses when you need to distinguish malformed syntax from expansion and command execution failures.