Skip to main content
Version: 2.0.x


The ZIOApp trait is an entry point for a ZIO application that allows sharing layers between applications. It also provides us the ability to compose multiple ZIO applications.

There is another simpler version of ZIOApp called ZIOAppDefault. We usually use ZIOAppDefault which uses the default ZIO environment (ZEnv).

Running a ZIO effect

The ZIOAppDefault has a run function, which is the main entry point for running a ZIO application on the JVM:

import zio._

object MyApp extends ZIOAppDefault {
def run = for {
_ <- Console.printLine("Hello! What is your name?")
n <- Console.readLine
_ <- Console.printLine("Hello, " + n + ", good to meet you!")
} yield ()

Accessing Command-line Arguments

ZIO has a service that contains command-line arguments of an application called ZIOAppArgs. We can access command-line arguments using the built-in getArgs method:

import zio._

object HelloApp extends ZIOAppDefault {
def run = for {
args <- getArgs
_ <-
if (args.isEmpty)
Console.printLine("Please provide your name as an argument")
Console.printLine(s"Hello, ${args.head}!")
} yield ()

Customized Runtime

In the ZIO app, by overriding its bootstrap value, we can map the current runtime to a customized one. Let's customize it by introducing our own executor:

import zio._
import zio.Executor
import java.util.concurrent.{LinkedBlockingQueue, ThreadPoolExecutor, TimeUnit}

object CustomizedRuntimeZIOApp extends ZIOAppDefault {
override val bootstrap = Runtime.setExecutor(
new ThreadPoolExecutor(
new LinkedBlockingQueue[Runnable]()

def run = myAppLogic

A detailed explanation of the ZIO runtime system can be found on the runtime page.

Installing Low-level Functionalities

We can hook into the ZIO runtime to install low-level functionalities into the ZIO application, such as logging, profiling, and other similar foundational pieces of infrastructure.

A detailed explanation can be found on the runtime page.

Composing ZIO Applications

To compose ZIO applications, we can use <> operator:

import zio._

object MyApp1 extends ZIOAppDefault {
def run = ZIO.succeed(???)

object MyApp2 extends ZIOAppDefault {
override val bootstrap: ZLayer[Any, Any, Any] =
asyncProfiler ++ slf4j ++ loggly ++ newRelic

def run = ZIO.succeed(???)

object Main extends ZIOApp.Proxy(MyApp1 <> MyApp2)

The <> operator combines the layers of the two applications and then runs the two applications in parallel.