
Loads and parses .env-style key-value files with non-modifying and environment-modifying APIs, configurable loader, reader support, multiline/substitution handling, and compile-time/runtime loading options.
A modern, zero-overhead Kotlin Multiplatform port of Rust's dotenvy.
Loads environment variables from .env files across JVM, Android, iOS, macOS, watchOS, tvOS, Linux, Windows, Node.js, and WebAssembly (WasmJS & WasmWASI).
allan2/dotenvy with full test parity..env or custom config files.km-io — Powered by io.github.kotlinmania:km-io with zero external C dependencies.${VAR} references dynamically across environment values and file definitions.dotenvy binary for wrapping commands with injected .env state.repositories {
mavenCentral()
}
dependencies {
implementation("io.github.kotlinmania:dotenvy-kotlin:0.1.3")
}repositories {
mavenCentral()
}
dependencies {
implementation 'io.github.kotlinmania:dotenvy-kotlin:0.1.3'
}<dependency>
<groupId>io.github.kotlinmania</groupId>
<artifactId>dotenvy-kotlin</artifactId>
<version>0.1.2</version>
</dependency>When integrating via Kotlin Multiplatform's Swift Export:
// Package.swift
dependencies: [
.package(path: "path/to/Dotenvy")
]The standard dotenv() function searches for .env in the current working directory or any of its parent directories, and injects the variables into the system environment:
import io.github.kotlinmania.dotenvy.dotenv
import io.github.kotlinmania.dotenvy.var_
fun main() {
// Searches up ancestor directories and injects variables into process environment
dotenv().getOrThrow()
// Retrieve variables with typed Result returns
val databaseUrl = var_("DATABASE_URL").getOrThrow()
val port = var_("PORT").getOrDefault("8080")
println("Connecting to $databaseUrl on port $port...")
}If you want to read variables without modifying the process environment, iterate over parsed pairs:
import io.github.kotlinmania.dotenvy.dotenvIter
fun loadConfiguration(): Map<String, String> {
val iter = dotenvIter().getOrThrow()
val config = mutableMapOf<String, String>()
for (entry in iter) {
val (key, value) = entry.getOrThrow()
config[key] = value
}
return config
}import io.github.kotlinmania.dotenvy.fromPath
import io.github.kotlinmania.dotenvy.fromPathOverride
import io.github.kotlinmania.dotenvy.fromFilename
import io.github.kotlinmania.io.files.Path
// Load specific path (does not overwrite existing environment variables)
fromPath(Path("config/.env.local")).getOrThrow()
// Force override existing environment variables with file values
fromPathOverride(Path("config/.env.override")).getOrThrow()
// Look for a custom filename walking up ancestor directories
fromFilename(".env.production").getOrThrow()import io.github.kotlinmania.dotenvy.Finder
import io.github.kotlinmania.io.files.Path
val iter = Finder()
.filename(Path(".env.staging"))
.loadIter()
.getOrThrow()
while (iter.hasNext()) {
val (key, value) = iter.next().getOrThrow()
println("$key=$value")
}import io.github.kotlinmania.dotenvy.fromRead
import io.github.kotlinmania.dotenvy.fromReadOverride
import io.github.kotlinmania.io.Buffer
import io.github.kotlinmania.io.writeString
val buffer = Buffer().apply {
writeString("""
HOST=localhost
PORT=5432
DB_USER=admin
DB_PASS=secret
DATABASE_URL=postgres://${"$"}{DB_USER}:${"$"}{DB_PASS}@${"$"}{HOST}:${"$"}{PORT}/mydb
""".trimIndent())
}
// Ingest directly from memory or network stream
fromRead(buffer).getOrThrow()dotenvy-kotlin conforms strictly to the .env standard:
# Lines beginning with '#' are ignored
KEY=value
ANOTHER_KEY=value with spaces # Inline comments are supported!# Single quotes preserve literal strings exactly
SINGLE_QUOTED='hello\nworld' # Literal \ and n, no escape evaluation
# Double quotes interpret escapes and preserve newlines
DOUBLE_QUOTED="hello\nworld"
# Multi-line strings inside quotes
CERTIFICATE="-----BEGIN CERTIFICATE-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END CERTIFICATE-----"Values can reference variables already defined in the environment or earlier in the file:
USER=alice
HOME_DIR=/home/${USER}
LOG_FILE=${HOME_DIR}/app.log
# Escape '$' with backslash to prevent substitution:
LITERAL_PRICE=\$100| Platform | Target Identifier | Architecture / Runtime |
|---|---|---|
| JVM | jvm |
Java 21+ bytecode |
| Android | android |
Android API 24+ (AAR) |
| Apple macOS | macosArm64 |
Apple Silicon (M1/M2/M3/M4) |
| Apple iOS |
iosArm64, iosSimulatorArm64
|
Device & Simulator |
| Apple watchOS |
watchosDeviceArm64, watchosSimulatorArm64
|
Apple Watch 64-bit |
| Apple tvOS |
tvosArm64, tvosSimulatorArm64
|
Apple TV |
| Linux |
linuxX64, linuxArm64
|
GNU / Linux |
| Windows | mingwX64 |
Windows x64 Native |
| JavaScript | js |
Node.js |
| WebAssembly |
wasmJs, wasmWasi
|
WebAssembly Browser & WASI Preview 1 |
dotenvy-kotlin exports native Swift types via Kotlin 2.4 Swift Export:
import Dotenvy
// Load .env from ancestor hierarchy
let _ = Dotenvy.dotenv()
// Look up values safely
if let host = try? Dotenvy.var_("HOST").get() {
print("Loaded host: \(host)")
}dotenvy-kotlin is derived from and inspired by the excellent work of the Rust open-source community:
allan2/dotenvy — Created and maintained by Allan Zhang (al@ayz.ai) as a robust, modern fork of the dotenv crate.dotenv-rs/dotenv — Original dotenv implementation authored by:
noemi.lapresta@gmail.com)chills@gmail.com)mfpiccolo@gmail.com)alice@alicemaz.com)sean@seantheprogrammer.com)adam@sharplet.me)arpad.borsos@googlemail.com)All design decisions, syntax rules, and algorithm invariants originate from these authors. We express our deepest gratitude for their foundational contributions to developer tooling.
This project is licensed under the MIT License to match the upstream dotenvy and dotenv licensing terms.
A modern, zero-overhead Kotlin Multiplatform port of Rust's dotenvy.
Loads environment variables from .env files across JVM, Android, iOS, macOS, watchOS, tvOS, Linux, Windows, Node.js, and WebAssembly (WasmJS & WasmWASI).
allan2/dotenvy with full test parity..env or custom config files.km-io — Powered by io.github.kotlinmania:km-io with zero external C dependencies.${VAR} references dynamically across environment values and file definitions.dotenvy binary for wrapping commands with injected .env state.repositories {
mavenCentral()
}
dependencies {
implementation("io.github.kotlinmania:dotenvy-kotlin:0.1.3")
}repositories {
mavenCentral()
}
dependencies {
implementation 'io.github.kotlinmania:dotenvy-kotlin:0.1.3'
}<dependency>
<groupId>io.github.kotlinmania</groupId>
<artifactId>dotenvy-kotlin</artifactId>
<version>0.1.2</version>
</dependency>When integrating via Kotlin Multiplatform's Swift Export:
// Package.swift
dependencies: [
.package(path: "path/to/Dotenvy")
]The standard dotenv() function searches for .env in the current working directory or any of its parent directories, and injects the variables into the system environment:
import io.github.kotlinmania.dotenvy.dotenv
import io.github.kotlinmania.dotenvy.var_
fun main() {
// Searches up ancestor directories and injects variables into process environment
dotenv().getOrThrow()
// Retrieve variables with typed Result returns
val databaseUrl = var_("DATABASE_URL").getOrThrow()
val port = var_("PORT").getOrDefault("8080")
println("Connecting to $databaseUrl on port $port...")
}If you want to read variables without modifying the process environment, iterate over parsed pairs:
import io.github.kotlinmania.dotenvy.dotenvIter
fun loadConfiguration(): Map<String, String> {
val iter = dotenvIter().getOrThrow()
val config = mutableMapOf<String, String>()
for (entry in iter) {
val (key, value) = entry.getOrThrow()
config[key] = value
}
return config
}import io.github.kotlinmania.dotenvy.fromPath
import io.github.kotlinmania.dotenvy.fromPathOverride
import io.github.kotlinmania.dotenvy.fromFilename
import io.github.kotlinmania.io.files.Path
// Load specific path (does not overwrite existing environment variables)
fromPath(Path("config/.env.local")).getOrThrow()
// Force override existing environment variables with file values
fromPathOverride(Path("config/.env.override")).getOrThrow()
// Look for a custom filename walking up ancestor directories
fromFilename(".env.production").getOrThrow()import io.github.kotlinmania.dotenvy.Finder
import io.github.kotlinmania.io.files.Path
val iter = Finder()
.filename(Path(".env.staging"))
.loadIter()
.getOrThrow()
while (iter.hasNext()) {
val (key, value) = iter.next().getOrThrow()
println("$key=$value")
}import io.github.kotlinmania.dotenvy.fromRead
import io.github.kotlinmania.dotenvy.fromReadOverride
import io.github.kotlinmania.io.Buffer
import io.github.kotlinmania.io.writeString
val buffer = Buffer().apply {
writeString("""
HOST=localhost
PORT=5432
DB_USER=admin
DB_PASS=secret
DATABASE_URL=postgres://${"$"}{DB_USER}:${"$"}{DB_PASS}@${"$"}{HOST}:${"$"}{PORT}/mydb
""".trimIndent())
}
// Ingest directly from memory or network stream
fromRead(buffer).getOrThrow()dotenvy-kotlin conforms strictly to the .env standard:
# Lines beginning with '#' are ignored
KEY=value
ANOTHER_KEY=value with spaces # Inline comments are supported!# Single quotes preserve literal strings exactly
SINGLE_QUOTED='hello\nworld' # Literal \ and n, no escape evaluation
# Double quotes interpret escapes and preserve newlines
DOUBLE_QUOTED="hello\nworld"
# Multi-line strings inside quotes
CERTIFICATE="-----BEGIN CERTIFICATE-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END CERTIFICATE-----"Values can reference variables already defined in the environment or earlier in the file:
USER=alice
HOME_DIR=/home/${USER}
LOG_FILE=${HOME_DIR}/app.log
# Escape '$' with backslash to prevent substitution:
LITERAL_PRICE=\$100| Platform | Target Identifier | Architecture / Runtime |
|---|---|---|
| JVM | jvm |
Java 21+ bytecode |
| Android | android |
Android API 24+ (AAR) |
| Apple macOS | macosArm64 |
Apple Silicon (M1/M2/M3/M4) |
| Apple iOS |
iosArm64, iosSimulatorArm64
|
Device & Simulator |
| Apple watchOS |
watchosDeviceArm64, watchosSimulatorArm64
|
Apple Watch 64-bit |
| Apple tvOS |
tvosArm64, tvosSimulatorArm64
|
Apple TV |
| Linux |
linuxX64, linuxArm64
|
GNU / Linux |
| Windows | mingwX64 |
Windows x64 Native |
| JavaScript | js |
Node.js |
| WebAssembly |
wasmJs, wasmWasi
|
WebAssembly Browser & WASI Preview 1 |
dotenvy-kotlin exports native Swift types via Kotlin 2.4 Swift Export:
import Dotenvy
// Load .env from ancestor hierarchy
let _ = Dotenvy.dotenv()
// Look up values safely
if let host = try? Dotenvy.var_("HOST").get() {
print("Loaded host: \(host)")
}dotenvy-kotlin is derived from and inspired by the excellent work of the Rust open-source community:
allan2/dotenvy — Created and maintained by Allan Zhang (al@ayz.ai) as a robust, modern fork of the dotenv crate.dotenv-rs/dotenv — Original dotenv implementation authored by:
noemi.lapresta@gmail.com)chills@gmail.com)mfpiccolo@gmail.com)alice@alicemaz.com)sean@seantheprogrammer.com)adam@sharplet.me)arpad.borsos@googlemail.com)All design decisions, syntax rules, and algorithm invariants originate from these authors. We express our deepest gratitude for their foundational contributions to developer tooling.
This project is licensed under the MIT License to match the upstream dotenvy and dotenv licensing terms.