Composable resource management in Scala

A story about safe and compositional resource management in vanilla Scala and cats-effect.

Bartłomiej Szwej
Apr 27 · 13 min read

We’re all using resources on a daily basis. You turn on the water tap, wash your hands for at least 20–30 seconds, and turn it off. You switch the light on if it’s dark, and off when you no longer need it.

Resources have a lifecycle. You open them, use them, and close them afterward. Not only light and water taps fall in that category, but also all kinds of database connections, HTTP servers, clients, files, or streams.

What’s interesting about resources is that they often depend on each other, so we care about the ordering of their acquisition and release. We want to see how we wash our hands, so we switch the light on before turning the water tap. If a database is used for processing HTTP requests, we want to connect to it first and after that, we start the HTTP server. However, during the application shutdown, we want to stop the HTTP server, and then close the database connection. In other words, we often want to release the resources in reverse acquisition order.

On top of that, we need to make sure we release all of them even if:

  • The program that uses resources throws an unhandled exception during its runtime.
  • Closing one out of many resources throws an unhandled exception.

Finally, we’d like to automate resource management. We shouldn't go through the code all over again to manually verify if we properly release them. Ideally, we should come up with a construct that does that automatically. It’d be awesome if both light and water tap would turn on/off itself as you’re approaching!

There are multiple ways to do resource management in Scala. We’ll start with the most basic ones and iteratively improve to achieve a fully compositional and safe way of dealing with them. In the end, we’ll see how to manage resources in purely functional programs with Cats Effect 2.x.

This article is dedicated to beginner and intermediate level Scala programmers. The source code shown in this blog post can be found in this repository. With all of that in mind, let’s start!

It all starts with… try-finally

try-finally is probably the most basic way of managing resources. We try to use them, and finally, whatever happens, we try to close them:

The code above wouldn’t differ much from its Java equivalent. try-finally is a construct that comes from and is meant to be used in the imperative world. This approach has the following disadvantages:

  • It’s not composable.
  • It’s manual. You have to always look at the code, and check if all the resources you acquire are closed.
  • It’s easy to forget about proper ordering when closing.
  • If we’re closing more resources in the finally block, and something throws an exception there, the rest of the resources would remain open.

How can we improve?

The Loaner Pattern

Next, we can use the so-called Loaner pattern to better manage resources:

The idea is to encapsulate resource management inside a function and delegate its usage to a closure (handle). In other words, to loan the resource to the handler.

It doesn’t differ much from the raw try-finally approach. However, what’s better is that the caller of withSqsConsumer doesn’t have to care about closing the resource.

If we had more resources, we could try to compose them by nesting:

We have a guaranteed ordering when closing resources, which is a reverse order of acquisition. It means that, in this case, we could observe the following order of acquisition/release:

The main drawback is that this approach does not compose well. Imagine how it would look with 10 or more resources. It’s definitely not scalable in terms of code structure, and would probably resemble something like a callback hell.

The Loaner pattern addresses some of the flaws we observed with try-catch. But what’s interesting here is that it looks as something we could generalize even more, and if done properly, we could drastically improve composability.

Introducing Resource

Let’s try to generalize the Loaner pattern to work for all kinds of resources:

What we did here is we introduced the type parameter R, which represents the resource and we extracted the close function. Notice that resource handle and close nicely describe the whole lifecycle of the value R.

But… we still didn’t solve the problem of composition!

It turns out we can take the above approach, and turn it into a nice abstraction. Meet the Resource:

We can use it in the following way:

The resource is meant to be used only inside the use block. Before/after that, it’s closed. If you leak it outside of use, that might throw an exception.

Now let’s think about how we could approach the problem of composition. As mentioned in the introduction, we often care about the order of acquisition/release, as resources can have dependencies between each other.

That means we’d like to compose our new data type sequentially, and sequential composition is the essence of… a Monad!

Creating a Monad[Resource] is not that hard, and we can follow the types here:

Each flatMap invocation creates a new Resource[B]. To open Resource[B], we have to first open Resource[A] with r.use. As you noticed, this is the essence of the sequential composition. We open A, and only after that we open B. Then, we define what happens after r is opened. We apply the mapping function and follow the types till the end.

That’s it! Now we can compose resources sequentially!

Side note on Monads

The Curse of Monad says, that once you get the epiphany, once you understand, you lose the ability to explain it to anybody. That’s probably why so many beginner functional programmers struggle with this concept… while they don’t really have to know anything about Monads in order to write functional programs.

To simply put, a Monad is all about running computations in sequence. In Scala, this sequencing is expressed using flatMap operation, or its syntactic sugar: for-comprehension. Option, Either, List, IO, Resource, and many more data types are in fact Monads.

def flatMap(fa: F[A])(f: A => F[B]): F[B] says:

To get F[B], first it needs to be returned by f: A => F[B]. But to return it, we need to supply A. And the only place where A comes can be F[A].

Monads come with laws. They’re just to make your life easier and avoid unnecessary surprises. Laws guarantee, that flatMap will behave in the same consistent way across all monads, e.g. Option, Resource, IO, …

We can also easily implement Functor[Resource] instance as well:

Functor, like Monad, is also a recurring pattern in functional programming. Functors are all data structures, that you can map. In fact, all Monads, are also Functors, but not the other way around.

Voilà, now we have flatMap and map operations defined on the Resource, so we can use for-comprehensions:

And it works exactly as we wanted:

We can use the property, that every Monad is an Applicative, and turn the above example into a nice applicative composition (if resources don’t depend on each other). We’ll see such an example later in this article when we’ll talk about resource management with cats-effect.

What we achieved here is:

  • sequential composition
  • an ordered resource release (in reverse order of acquisition)
  • automated resource management
  • closing all resources if our program fails with an exception
  • handling edge situations when closing one of the resources throws an exception. In this case, all other resources are closed, which is good.

It turns out, that a similar concept of resource already exists in Haskell and in Scala libraries for some time.

Of course, the Resource[R] we designed is very simplistic, just to give you an idea. It’d be hard to use when asynchrony comes into play, hence we can’t really use it with modern effect types like ZIO, Monix Task, or Cats IO.

Luckily, all the above effect types have mechanisms to deal with resource management. The good news is as soon as we see them, and we’ll immediately notice some resemblance.

Resource management with Cats Effect

cats-effect is a library that comes with building blocks for modeling effectful computations. In other words, it allows you to write purely functional programs, that do side-effects like:

  • Communicating with different services over the network.
  • Keeping and modifying its internal state.

cats-effect consists of two parts:

  • cats IO — a fully composable data type, that allows you to hide (suspend) side-effects inside. Think of it as an alternative to Monix Task, or ZIO. Think of it as Future, but rather in a wide approximation.
  • type classes, which describe the shape of an arbitrary effect type. What it means is that you can write programs or libraries in terms of them, and later supply other compatible¹ effect types (e.g. Cats IO, Monix Task, ZIO, …).

[1] the ones for which cats-effect type class instances are defined.

Daniel Spiewak defines it in the following way:

Image for post
Image for post
Slide from the recent talk Cats Effect 3: What, When, Why presented during Scala Love conference

cats-effect comes with two handy mechanisms of dealing with resources: bracket and resource.

But for now, let’s see how we’d manage resources without them, and what could be the potential problems.

By default, we can just treat resources any other kind of value:

and this could work fine:

Now let’s modify the business logic to raise an unexpected error:

As a result, we are not closing the resource:

Ok, you might say we can just attempt , and then rethrow again after we close the resource:

And there we go, the program explodes and the resource is closed:

But... there is one detail we missed. IO is cancellable and that means we can stop it in the middle of execution. In this case, we’d also want to, no matter what, release all the resources involved. We can demonstrate it in the following way:

and what we get is:

As you can see, we do not release any resources if IO gets canceled. For that, we’d probably need something more advanced. We could obviously experiment with using timeoutTo, and falling back another IO that does the cleanup, but this is not where we want to go.


Meet the bracket. Bracket comes from Haskell, and is a type class in cats-effect dedicated to safe and automatic resource management:

What the docs say is:

Bracket is an extension of MonadError exposing the bracket operation, a generalized abstracted pattern of safe resource acquisition and release in the face of errors or interruption.

That sounds like a solution to the problem with errors and cancellations mentioned above. Let’s see it in action:

Nice! We just squashed a bunch of lines into just a single construct, gaining full safety along the way!

When business logic raises an error, then we’re covered:

The same applies to cancellations:

Now let’s add more resources into play, and let’s see how the code would scale:

It turns out that with Bracket we stumble upon the same problem as with the Loaner pattern. Our code becomes unmanageable with more resources due to the lack of composition. Although we have fully automated and safe resource management, we can’t really compose it nicely. And this is where another abstraction comes into play, the Resource.

Note: I’m not saying that using Bracket is wrong. It provides safe resource management when working with IO and is fairly simple. It might work nicely when working a single resource, but with more of them, it might be just cumbersome to use.


Meet the Resource. This is a data structure we already discovered before. You already know that Resource forms a Monad, hence it can be composed sequentially. And with this property, we can nicely structure our code no matter how it grows!

The definition of Resource in cats-effect is just slightly different than ours. In cats-effect world, everything revolves around IO, and corresponding type classes. The same applies for Resource:

The structure resembles the Resource we derived in the former part of the article, but this one requires F[_], which denotes the effect type. That’s because Resource in cats-effect is meant to be used with different effect types (Cats IO, ZIO etc.).

Let’s see how to initialize multiple resources:

and it works fine. What’s interesting is that now the whole program is in the Resource context, and not IO. That’s why we used liftF to lift our business logic into Resource[F[_], A]. This shouldn’t be a surprise for a cats user.

Now, if the business logic raises an exception:

Then all resources are closed:

On the other hand, if one of the release operations raises an exception:

Then the rest would be closed normally:

One last thing. What if you have a bunch of independent resources you’d like to compose? Again, it’s not a problem for Resource. You can just use applicative composition:

That’s it! Resource gives us extra safety, composes nicely, and does all of that automatically. I encourage you to look into the Resource source code. For example, you can find many useful constructors, like fromAutoCloseable , or fromAutoCloseableBlocking that might help when dealing with Java APIs.

Bonus: bootstrapping a microservices using Resource

Below you can find a bigger example of the Resource being used while bootstrapping a microservice application, that uses cats-effect, http4s, and Doobie. The full runnable version can be found here.


We started with the simplest approach, which is try-finally, and iteratively improved until discovering the Resource. We learned that it’s a data structure that guarantees safety, proper release order, and also composes very well.

In the end, we saw how to deal with resources using Bracket and Resource in purely functional programs using cats-effect. We noticed that those mechanisms are very reliable and they met our initial expectations:

  • Sequential composition.
  • Automatic release in reverse order of acquisition.
  • Closing all resources automatically no matter whether the program completes with success, raises with an exception, or is canceled.
  • Handling edge situations when closing one of the resources out of many raises an exception.

Thanks for reading and happy coding!

Further reading

Special thanks @sinisalouc for proofreading and making this article better.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

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