kotlin-app-config

Kotlin Application Configuration Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "kotlin-app-config" with this command: npx skills add navikt/copilot/navikt-copilot-kotlin-app-config

Kotlin Application Configuration Skill

This skill provides patterns for type-safe environment configuration using Kotlin sealed classes.

Sealed Class Configuration Pattern

sealed class Environment( val name: String, val databaseUrl: String, val kafkaBrokers: String, val azureAdIssuer: String ) { data object Local : Environment( name = "local", databaseUrl = "jdbc:postgresql://localhost:5432/myapp", kafkaBrokers = "localhost:9092", azureAdIssuer = "http://localhost:8080/azuread" )

data class Dev(
    private val env: Map<String, String>
) : Environment(
    name = "dev",
    databaseUrl = env.getValue("DATABASE_URL"),
    kafkaBrokers = env.getValue("KAFKA_BROKERS"),
    azureAdIssuer = env.getValue("AZURE_OPENID_CONFIG_ISSUER")
)

data class Prod(
    private val env: Map<String, String>
) : Environment(
    name = "prod",
    databaseUrl = env.getValue("DATABASE_URL"),
    kafkaBrokers = env.getValue("KAFKA_BROKERS"),
    azureAdIssuer = env.getValue("AZURE_OPENID_CONFIG_ISSUER")
)

companion object {
    fun from(env: Map<String, String>): Environment {
        return when (env["Nais_CLUSTER_NAME"]) {
            "dev-gcp" -> Dev(env)
            "prod-gcp" -> Prod(env)
            else -> Local
        }
    }
}

}

Using Configuration

fun main() { val env = Environment.from(System.getenv())

val dataSource = createDataSource(env.databaseUrl)
val kafkaProducer = createKafkaProducer(env.kafkaBrokers)

logger.info("Starting application in ${env.name} environment")

}

With Konfig Library

import com.natpryce.konfig.*

data class AppConfig( val database: DatabaseConfig, val kafka: KafkaConfig, val azure: AzureConfig )

data class DatabaseConfig( val url: String,

Alternative: Sealed Interface Pattern (navikt/hotlibs)

Production pattern from navikt/hotlibs supporting multiple cluster types:

sealed interface Environment { val cluster: String val tier: Tier

enum class Tier { TEST, LOCAL, DEV, PROD }

companion object {
    private val all: List<Environment> = listOf(
        TestEnvironment,
        LocalEnvironment,
        GcpEnvironment.DEV,
        GcpEnvironment.PROD
    )

    val current: Environment by lazy {
        val cluster = System.getenv("Nais_CLUSTER_NAME")
        all.find { it.cluster == cluster } ?: LocalEnvironment
    }
}

}

sealed class DefaultEnvironment( override val cluster: String, override val tier: Environment.Tier ) : Environment

object TestEnvironment : DefaultEnvironment("test", Environment.Tier.TEST) object LocalEnvironment : DefaultEnvironment("local", Environment.Tier.LOCAL)

enum class GcpEnvironment( override val cluster: String, override val tier: Environment.Tier ) : Environment { DEV("dev-gcp", Environment.Tier.DEV), PROD("prod-gcp", Environment.Tier.PROD) }

data class DatabaseConfig( val url: String, val username: String, val password: String )

data class KafkaConfig( val brokers: String, val topic: String )

data class AzureConfig( val clientId: String, val issuer: String, val jwksUri: String )

fun loadConfig(): AppConfig { val config = ConfigurationProperties.systemProperties() overriding EnvironmentVariables()

return AppConfig(
    database = DatabaseConfig(
        url = config[Key("database.url", stringType)],
        username = config[Key("database.username", stringType)],
        password = config[Key("database.password", stringType)]
    ),
    kafka = KafkaConfig(
        brokers = config[Key("kafka.brokers", stringType)],
        topic = config[Key("kafka.topic", stringType)]
    ),
    azure = AzureConfig(
        clientId = config[Key("azure.client.id", stringType)],
        issuer = config[Key("azure.issuer", stringType)],
        jwksUri = config[Key("azure.jwks.uri", stringType)]
    )
)

}

Benefits

  • Type Safety: Compile-time validation of configuration

  • Environment Separation: Clear boundaries between local/dev/prod

  • Testability: Easy to create test configurations

  • Documentation: Configuration structure is self-documenting

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

aksel-spacing

No summary provided by upstream source.

Repository SourceNeeds Review
General

flyway-migration

No summary provided by upstream source.

Repository SourceNeeds Review
General

tokenx-auth

No summary provided by upstream source.

Repository SourceNeeds Review
General

observability-setup

No summary provided by upstream source.

Repository SourceNeeds Review