Skip to main content
Version: 2.0.x

Read from various Sources

zio-config supports various sources.

import zio._, Config._, ConfigProvider._
import zio.config._, magnolia._
case class MyConfig(ldap: String, port: Int, dburl: String)
val myConfig =
(string("LDAP") zip int("PORT") zip string("DB_URL")).to[MyConfig]

// val automatedConfig = deriveConfig[MyConfig]; using zio-config-magnolia

HOCON String

To enable HOCON source, you have to bring in zio-config-typesafe module. There are many examples in examples module in zio-config.

Here is an quick example

import zio.config.typesafe._
import zio.config.magnolia._
case class SimpleConfig(port: Int, url: String, region: Option[String])

val automaticDescription = deriveConfig[SimpleConfig]

val hoconSource =
port : 123
url : bla
region: useast


val anotherHoconSource =


// yielding SimpleConfig(123,bla,Some(useast))




You can use zio-config-typesafe module to fetch json as well

val jsonString =
"port" : "123"
"url" : "bla"
"region": "useast"



Yaml FIle

Similar to Hocon source, we have ConfigProvider.fromYamlString

import zio.config.yaml._


Xml String

zio-config can read XML strings. Note that it's experimental with a dead simple native xml parser, Currently it cannot XML comments, and has not been tested with complex data types, which will be fixed in the near future.

import zio.config.xml.experimental._
import zio.Config

final case class Configuration(aws: Aws, database: Database)

object Configuration {
val config: Config[Configuration] =

final case class Aws(region: String, account: String)

object Aws {
val config: Config[Aws] = Config.string("region").zip(Config.string("account")).to[Aws]
final case class Database(port: Int, url: String)

object Database {
val config: Config[Database] ="port").zip(Config.string("url")).to[Database]

val config =
| <aws region="us-east" account="personal"></aws>
| <database port="123" url="some url"></database>

val parsed = ConfigProvider.fromYamlString(config).load(Configuration.config)

Indexed Map, Array datatype, and a some implementation notes

zio-config comes up with the idea of IndexedFlat allowing you to define indexed configs (see examples below). However, the constructors of IndexedFlat is not exposed to the user for the time being, since it can conflate with some ideas in zio.core Flat, and resulted in failures whenever IndexedFlat was converted to a Flat internally. Example:

Therefore, some of these ideas around Indexing is pushed back to ZIO and incorporated within the Flat structure.

See and

These changes are to keep the backward compatibility of ZIO library itself.

What does it mean to users?

It implies, for sequence (or list) datatypes, you can use either <nil> or "" to represent empty list in a flat structure. See the below example where it tries to mix indexing into flat structure. We recommend using <nil> over "" whenever you are trying to represent a real indexed format


import zio.config._, magnolia._

final case class Department(name: String, block: Int)

final case class Employee(departments: List[Department], name: String)
final case class Config(employees: List[Employee])

val map =
"employees[0].name" -> "jon",
"employees[0].departments[0].name" -> "science",
"employees[0].departments[0].block" -> "10",
"employees[0].departments[1].name" -> "maths",
"employees[0].departments[2].block" -> "11",
"employees[1].name" -> "foo",
"employees[1].departments" -> "<nil>",


Although we support indexing within Flat, formats such as Json/HOCON/XML is far better to work with indexing, and zio-config supports these formats making use of the above idea.

Another simple example of an indexed format

import zio.config._, magnolia._

final case class Employee(age: Int, name: String)

val map =
"department.employees[0].age" -> "10",
"department.employees[0].name" -> "foo",
"department.employees[1].age" -> "11",
"department.employees[1].name" -> "bar",
"department.employees[2].age" -> "12",
"department.employees[2].name" -> "baz",

val provider = ConfigProvider.fromMap(map)
val config = Config.listOf("employees", deriveConfig[Employee]).nested("department")
val result = provider.load(config)