What are the benefits of the ZIO modules with ZLayers

Three months ago I wrote this Blog:

Meanwhile ZIO took really of and one of my concerns got a major update with RC18:

I still struggle with ZIO, for example providing the runtime/ environment…

So I updated all my ZIO projects with ZLayers!

In this Blog I will focus on my experiences I made when migrating to the new Modules and Layers of ZIO.

Spoiler: The migration was straight forward!

I structured this Blog in three parts:

  1. Listing the Module parts as they were in my project.
  2. Showing them after migrating to ZLayer.
  3. List my personal improvements of ZLayer.

1. Old Style

As I don’t have a cat — a Bike photo 😏

So how did a Module look like before RC18? I just extracted the main parts of the official documentation. And there were quite some parts:

The Components trait is the module, which is just a container for the Components.Service.

The service is just an ordinary interface, defining the capabilities it provides.

  • By convention it is in the modules companion object.
  • R is for the environment which you define for the whole Service.
  • You can have different environments for different Service Implementations.

The Access Methods allow you to use the Service without knowing which Implementation it gonna be. As you can see they are in a strangely named object. For example:Components.>.render(myComp)

Each implementation can specify its own requirements (environment R). In our example ComponentsEnv which resolves to the standard Console.

The program itself does not care what its implementation is. All it says it requires an AppEnv in the end.

And here at last we provide our Program with the implementations. As seen above it requires aConsole and a Components implementation.

2. New Style

Ok, now the actual part we are exited about.

So let’s see if ZLayers are so awesome.

I will not explain the different concepts and data types, as they are well explained in the official documentation.

The Components is just a type alias for the ‘module’, which describes a dependency to the service Components.Service.

Has[A] represents a dependency on a service of type A.

The only difference here is that the environment R is not set on the Service but on the methods. So each functionality defines its on requirements.

Also interesting is that all Service implementations have the same requirements. This means if you need different environments in your implementation, you cannot provide it via the environment R anymore.

Nothing much changed here:

  • There is no extra object for the Access Methods.
  • The Service instance is retrieved from the HasSyntax with some magic.

The implementation is now just creating a ZLayer with a Service.

In our case as we have different Service implementations we provide a function that takes a Service implementation and creates a ZLayer from it.

The Service implementation looks the same as before, except that we do not need to implement the whole Module anymore!

No change here, I had only to adjust the imports. From Components.>.{load, render}toComponents.{load, render}.

Two things have changed:

  • We must not provide the standard environment Console.
  • We call the function that creates our ZLayer with our Service Implementation.

There was one thing that I did not grasp at first. If the Service implementation can not have its own environment R. How would you achieve this now?

My first thought was to just add it to the Service definition.

This implies that every implementation needs to be adjusted, if you want to add an environment (e.g. Clock). So no that would be really bad.

Ok why not just add it as a dependency, like:

Better, but now the question arises — why would we need the environment at all?

The answer of course was Composing ZLayers vertically. So our implementation looks now:

And here is how you can provide it:


Here are my personal Top five improvements of this redesign:

  1. The Environment is now set on each Functionality. So not all functionalities must have the same Requirements. Also the whole setup is now much cleaner without R everywhere — or was it Any😏.
  2. Composing ZLayers horizontally and vertically.
  3. A module does not need to be implemented, just its Services.
  4. All Implementations have the same method signatures (same environment). Extra requirements can be added via vertical composition or as dependencies. This is more logical for me.
  5. Providing the environment is simpler, as the standard Environments are already provided, so you have only to provide your own custom ZLayers.


This update makes modules more accessible and likely to be adopted. One step closer to production ready.

And yes ZLayers are awesome — can’t wait for ZIO Release 1.0!


The Github Projects that I migrated and used in this Blog:

I migrated the Github project according to this documentation:

The old version of the module doc can be found here:

The images are from Central Switzerland — so if you are in the region && (want to Bike || talk about ZIO) > let me know😏.

Working for finnova.com in the Banking business. Prefer to work with Scala / ScalaJS.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store