Build Status Coverage Status License Download


Cfg4k is a configuration library made for Kotlin in Kotlin!


  • Automatic reload
  • Interface binding
  • Huge flexibility, custom sources
  • Easy to use
  • Bytebuddy provider will be able to compile your bindings at runtime (You will need to add the cfg4k-bytebuddy to your dependencies.)



Quick start

  1. Add the Bintray repository:
    repositories {
  2. Add the dependency for the module(s) that you are going to use
    compile 'com.jdiazcano.cfg4k:cfg4k-core:0.8.5'


Look better and more complete examples take a look at the examples module

import PropertyConfigLoader
import com.jdiazcano.cfg4k.providers.ProxyConfigProvider

fun main(args: Array<String>) {
    val loader = PropertyConfigLoader("/")) // Create loader
    val provider = ProxyConfigProvider(loader)                                                      // Create provider
    val databaseConfig = provider.bind<DatabaseConfig>("database")                            // bind and use

    println("Name: ${}")
    println("Url: ${databaseConfig.url()}")
    println("Port: ${databaseConfig.port()}")

 * This interface defines a database configuration
interface DatabaseConfig {
     * You can have javadocs inside your properties and this is really cool
    fun url(): String
    fun port(): Int
    fun name(): String

    // if you have an unused property you know it and you can delete it
    val unused: String

    @Deprecated("You can even deprecate properties!")
    fun deprecated(): Boolean
    val youCanuseValuesToo: String
    val andNullables: Int?

Detailed features


  1. DefaultConfigProvider: Base class for all the other providers. It has the basic functionality for a Provider. (You can obviously ignore it if implementing a new provider)
  2. CachedConfigProvider: This provider will cache the calls into a map and use the cached one once the same call is done again. When the method reload is called this cache will be cleared.
  3. OverrideConfigProvider: With this provider you can input a list of Loaders in order of precedence and it will return the first one that is not null/empty. So you can override properties for example: EnvironmentConfigLoader -> JsonConfigLoader it would pick first from Environment and then from Json.


  1. File system
  2. Classpath
  3. Git
  4. URL
  5. Future: S3
  6. BitbucketConfigSource
  7. GithubConfigSource


  1. ProxyBinder: Uses Java InvocationHandler in order to implement the interface and intercept the calls to return the correct value.
  2. ByteBuddyBinder: Uses ByteBuddy to create a class that implements the interface and returns the value.


  1. DefaultConfigLoader: This loader can take static map or vararg of pairs to create a loader from it.
  2. JsonConfigLoader: Load the properties from a Json file.
  3. PropertyConfigLoader: Load the properties from a Java properties file.
  4. EnvironmentConfigLoader: Load the properties from the Environment Variables. This will transform the environment variables so they can be used inside the project and stay consistent with the rest of the properties. For example having the variable GLOBAL_URL will result in the property global.url
    1. _ will become .
    2. - will become .
    3. The property name will become lowercase
  5. HoconConfigLoader: Load the properties from a Hocon file. This has many advantages over Json or Property (it is a superset of both) so I recommend this loader but not before taking a look at the project:
  6. YamlConfigLoader: Load the properties from a Yaml file.
  7. GitConfigLoader: Load the properties from a Git repository, possible giving the branch name or folder to denote different environments.

Reload strategies

  1. TimedReloadStrategy: This will reload the properties on a time basis.
  2. FileChangeReloadStrategy: This will reload when a file content has changed. This will only look for edits on the file that is passed as argument and this should be the same file than in the ConfigLoader


These parsers are supported out of the box

  1. Int
  2. Long
  3. Double
  4. Short
  5. Float
  6. Double
  7. Byte
  8. String
  9. Boolean
  10. List
  11. Set
  12. Enum
  13. BigInteger
  14. BigDecimal
  15. LocalDateTime
  16. LocalDate
  17. ZonedDateTime
  18. OffsetDateTime
  19. OffsetTime
  20. Calendar
  21. Date
  22. URI
  23. URL
  24. File
  25. Path
  26. Class<*>
  27. Regex
  28. Pattern
  29. InetAddress
  30. Connection
  31. Driver
  32. UUID

Customizing Cfg4k


Sources is an interface that must return an InputStream which is the stream of the data to load. It will be used to be injected in a Loader as the Loader is the one that knows how to use that data.


You can create your own config loader by implementing the ConfigLoader interface (or extending DefaultConfigLoader which provides the base code for “get”)

open class SystemPropertyConfigLoader : ConfigLoader {
    override fun reload() {
        // Nothing to do, the do the reload for us!

    override fun get(key: String): ConfigObject {
        return System.get(key, "").toConfig()


More examples in the package loaders


You can create your own Providers by implementing ConfigProvider or extending DefaultConfigProvider, keep in mind that the default provider already has the parsing so it is always a good practice to extend it.

Example of how caching properties can be done with the CachedConfigProvider

class CachedConfigProvider(val configProvider: ConfigProvider) : ConfigProvider by configProvider {
    private val cache = mutableMapOf<String, Any>()

    init {
        configProvider.addReloadListener { cache.clear() }

    override fun <T : Any> get(name: String, type: Class<T>, default: T?): T {
        if (cache.containsKey(name)) {
            return cache[name] as T
        } else {
            val property = configProvider.get(name, type, default)
            cache[name] = property
            return property

    override fun <T: Any> get(name: String, type: Typable, default: T?): T {
        if (cache.containsKey(name)) {
            return cache[name] as T
        } else {
            val property: T = configProvider.get(name, type, default)
            cache[name] = property
            return property

    override fun <T: Any> bind(prefix: String, type: Class<T>): T {
        // This is using %pre. in order to not collide with general properties
        val cachePrefix = "%pre.$prefix"
        if (cache.containsKey(cachePrefix)) {
            return cache[cachePrefix] as T
        } else {
            val property: T = configProvider.bind(prefix, type)
            cache[cachePrefix] = property
            return property

More examples in the package providers

Reload strategies

You can create your own reloading strategy by implementing the ReloadStrategy interface. Remember that you have to use it then in the provider.

class TimedReloadStrategy(val time: Long, val unit: TimeUnit) : ReloadStrategy {

    private lateinit var reloadTimer: Timer

    override fun register(configProvider: ConfigProvider) {
        reloadTimer = timer("TimeReloadStrategy", true, unit.toMillis(time), unit.toMillis(time)) {

    override fun deregister(configProvider: ConfigProvider) {


There are two steps in order to use a new parser (this is mostly used for parsing basic types and interfaces should be used instead of parsers!).

  1. Create your class by implementing Parser
  2. Register your parser in the Parsers class addParser()

See examples

* Have in mind that not everything is supported in code coverage in Kotlin (inline extension functions) so the code coverage might appear worse than it really is!


Licensed under the Apache License, Version 2.0. See LICENSE file.

compile "com.github.jdiazcano:cfg4k:0.8.5"

Related Libraries


Kotlin extensions for Java 8 java.time API

Last updated 3 mins ago


Vavr integration for Kotlin

Last updated 3 mins ago


Minimalist dependency injection library for Kotlin.

Last updated 3 mins ago


Simple unit conversion library for Kotlin

Last updated 3 mins ago


Simple parser combinator library for Kotlin

Last updated 3 mins ago