scalabeginner

Typesafe Config Parsing

Load and parse application configuration with Typesafe Config: HOCON format, defaults, and validation.

scala
import com.typesafe.config.{Config, ConfigFactory}
import scala.jdk.CollectionConverters.*
import scala.util.Try

case class DatabaseConfig(
  host: String,
  port: Int,
  name: String,
  pool: PoolConfig
)

case class PoolConfig(
  minSize: Int,
  maxSize: Int,
  timeout: Long
)

case class ServerConfig(
  host: String,
  port: Int,
  maxConnections: Int
)

case class AppConfig(
  server: ServerConfig,
  database: DatabaseConfig,
  features: Set[String]
)

object AppConfig:
  def load(): AppConfig =
    val config = ConfigFactory.load()
    fromConfig(config)

  def fromConfig(config: Config): AppConfig =
    AppConfig(
      server = ServerConfig(
        host = config.getString("app.server.host"),
        port = config.getInt("app.server.port"),
        maxConnections = config.getInt("app.server.max-connections")
      ),
      database = DatabaseConfig(
        host = config.getString("app.database.host"),
        port = config.getInt("app.database.port"),
        name = config.getString("app.database.name"),
        pool = PoolConfig(
          minSize = config.getInt("app.database.pool.min-size"),
          maxSize = config.getInt("app.database.pool.max-size"),
          timeout = config.getDuration("app.database.pool.timeout").toMillis
        )
      ),
      features = config.getStringList("app.features").asScala.toSet
    )

  // With defaults and overrides
  def loadWithOverrides(overrides: Map[String, String]): AppConfig =
    val baseConfig = ConfigFactory.load()
    val overrideConfig = ConfigFactory.parseMap(overrides.asJava)
    fromConfig(overrideConfig.withFallback(baseConfig))

// Example HOCON config (application.conf):
// app {
//   server {
//     host = "0.0.0.0"
//     host = ${?SERVER_HOST}
//     port = 8080
//     port = ${?SERVER_PORT}
//     max-connections = 1000
//   }
//   database {
//     host = "localhost"
//     port = 5432
//     name = "myapp"
//     pool {
//       min-size = 5
//       max-size = 20
//       timeout = 30s
//     }
//   }
//   features = ["auth", "cache", "metrics"]
// }

@main def run(): Unit =
  // Parse from string for demo
  val hocon = """
    |app {
    |  server { host = "0.0.0.0", port = 8080, max-connections = 500 }
    |  database {
    |    host = "db.local", port = 5432, name = "demo"
    |    pool { min-size = 2, max-size = 10, timeout = 15s }
    |  }
    |  features = ["auth", "logging"]
    |}
  """.stripMargin

  val config = AppConfig.fromConfig(ConfigFactory.parseString(hocon))
  println(s"Server: ${config.server.host}:${config.server.port}")
  println(s"DB: ${config.database.host}:${config.database.port}/${config.database.name}")
  println(s"Pool: ${config.database.pool.minSize}-${config.database.pool.maxSize}")
  println(s"Features: ${config.features}")

Use Cases

  • Application configuration management
  • Environment-specific configs
  • Type-safe config loading

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.