In day-to-day programming we quite often end up with data inside nested effects, e.g. an integer inside an Either, which in turn is nested inside an Option:

val x: Option[Validated[String, Int]] = Some(Valid(123))

This can be quite annoying to work with, as you have to traverse the nested structure every time you want to perform a map or something similar:
// res0: Option[Validated[String, String]] = Some(Valid("123"))

Nested can help with this by composing the two map operations into one:

import cats.implicits._
val nested: Nested[Option, Validated[String, *], Int] = Nested(Some(Valid(123)))
// res1: Option[Validated[String, String]] = Some(Valid("123"))

In a sense, Nested is similar to monad transformers like OptionT and EitherT, as it represents the nesting of effects inside each other. But Nested is more general - it does not place any restriction on the type of the two nested effects:

final case class Nested[F[_], G[_], A](value: F[G[A]])

Instead, it provides a set of inference rules based on the properties of F[_] and G[_]. For example:

  • If F[_] and G[_] are both Functors, then Nested[F, G, *] is also a Functor (we saw this in action in the example above)
  • If F[_] and G[_] are both Applicatives, then Nested[F, G, *] is also an Applicative
  • If F[_] is an ApplicativeError and G[_] is an Applicative, then Nested[F, G, *] is an ApplicativeError
  • If F[_] and G[_] are both Traverses, then Nested[F, G, *] is also a Traverse

You can see the full list of these rules in the Nested companion object.

A more interesting example

(courtesy of Channing Walton and Luka Jacobowitz via Twitter, slightly adapted)

Say we have an API for creating users:

import scala.concurrent.Future

case class UserInfo(name: String, age: Int)
case class User(id: String, name: String, age: Int)

def createUser(userInfo: UserInfo): Future[Either[List[String], User]] =
  Future.successful(Right(User("user 123",, userInfo.age)))

Using Nested we can write a function that, given a list of UserInfos, creates a list of Users:

import scala.concurrent.Await
import scala.concurrent.duration._
import cats.Applicative
import cats.implicits._

def createUsers(userInfos: List[UserInfo]): Future[Either[List[String], List[User]]] =
  userInfos.traverse(userInfo => Nested(createUser(userInfo))).value

val userInfos = List(
  UserInfo("Alice", 42),
  UserInfo("Bob", 99)
Await.result(createUsers(userInfos), 1.second)
// res2: Either[List[String], List[User]] = Right(
//   List(User("user 123", "Alice", 42), User("user 123", "Bob", 99))
// )

Note that if we hadn’t used Nested, the behaviour of our function would have been different, resulting in a different return type:

def createUsersNotNested(userInfos: List[UserInfo]): Future[List[Either[List[String], User]]] =
Await.result(createUsersNotNested(userInfos), 1.second)
// res3: List[Either[List[String], User]] = List(
//   Right(User("user 123", "Alice", 42)),
//   Right(User("user 123", "Bob", 99))
// )