Read on for a solution to loading environment variables from a .env
file. The code is for Kotlin, but should be easy to replicate in other stacks as well. No frameworks, low complexity. π
I try to not add frameworks or libraries unless they add great value. Of course I don’t want to re-invent the wheel, but there is always more complexity and limitations to the libraries than you first think. And then it is a chore to replace it.
Start small and expand. π
A lot of things are really not that complex to write code for. Application configs are one of those things. Even working across Gradle and local development in your IDE.
Get a variable from a file, if it exists in the ENV; use that instead. It’s that simple. π Need something a bit fancier? Just extend the code, you can do it. π
So here’s the Kotlin code for a config with the code to load it. Just one key here, but you get the gist of it:
data class ApplicationConfig(
val lookupApiKey: String
) {
companion object {
fun load(): ApplicationConfig {
fun Map<String, String>.envOrLookup(key: String): String {
return System.getenv(key) ?: this[key]!!
}
val envVars: Map<String, String> = envFile().let { envFile ->
if (envFile.exists()) {
envFile.readLines()
.map { it.split("=") }
.filter { it.size == 2 }
.associate { it.first().trim() to it.last().trim() }
} else emptyMap()
}
return ApplicationConfig(
lookupApiKey = envVars.envOrLookup("LOOKUP_API_KEY")
)
}
}
}
KotlinThe config is loaded in tests and in the KTor setup by calling the load function like this:
fun Application.module() {
configureHTTP()
configureMonitoring()
configureSerialization()
configureRouting()
// Manual dependency injection :) Usually smart to find a separate place to do this from KTor
val config = ApplicationConfig.load()
val mainPage = MainPage(LookupClient(config.lookupApiKey))
val selectedPage = SelectedPage()
// Load pages
configurePageRoutes(mainPage, selectedPage)
}
KotlinAs a bonus, you also see manual dependency injection. It really works. π And it really helps keeping the compiler give real feedback when something changed that needs to be updated.
You can find a complete application with this code working here: https://github.com/anderssv/kotlin-htmx/blob/ef6559473f1d246a914c98160a03bdc3644f6749/src/main/kotlin/no/mikill/kotlin_htmx/Application.kt#L16
Thoughts? Let me know.
This is just one of many things I do to avoid complexity so stay tuned and subscribe for the next thing.