0Pricing
Scala for Backend Engineering & Functional Programming · Lesson

The IO Monad

Pure effects.

The IO Monad is a free Scala for Backend Engineering & Functional Programming lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Scala for Backend Engineering & Functional Programming learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is IO?

IO[A] from Cats Effect is a description of a computation that, when run, may perform side effects and produce a value of type A. It is a pure value — nothing happens until you run it.

Deferring Side Effects

Wrap a side effect with IO(...) or IO.delay(...). The body is not executed when the IO is created — only when it is run.

import cats.effect.IO

val program: IO[Unit] = IO(println("Hello, IO!"))
// Nothing printed yet — program is just a description

Referential Transparency

Because IO is lazy, you can substitute an IO value for its definition without changing behavior. This referential transparency makes effectful code easier to reason about and refactor.

Pure Values

Use IO.pure to lift an already-computed value. Do not put side effects inside pure — it evaluates eagerly. Use IO.delay or IO(...) for effects.

import cats.effect.IO

val p: IO[Int] = IO.pure(42)
// 42 is computed already; pure just wraps it

map and as

map transforms the result of an IO. as replaces it with a constant. Neither runs the effect — they build a bigger description.

import cats.effect.IO

val len: IO[Int] = IO("hello").map(_.length)
val done: IO[String] = IO(println("ran")).as("done")

Running with IOApp

To execute an IO program, extend IOApp and implement run, returning an IO[ExitCode]. The runtime evaluates it on a fiber-based scheduler.

import cats.effect.{IO, IOApp, ExitCode}

object Main extends IOApp {
  def run(args: List[String]): IO[ExitCode] =
    IO(println("Running!")).as(ExitCode.Success)
}

IOApp.Simple

For programs without args or custom exit codes, extend IOApp.Simple and provide a run: IO[Unit].

import cats.effect.{IO, IOApp}

object Hello extends IOApp.Simple {
  def run: IO[Unit] = IO.println("Hello, world!")
}

IO.println

Cats Effect provides IO.println as a convenient effectful print. It returns IO[Unit] and only prints when run.

import cats.effect.IO

val greet: IO[Unit] = IO.println("effectful output")

Capturing Exceptions

If the wrapped effect throws, the failure is captured inside the IO instead of escaping. The IO becomes a failed value you can later handle.

import cats.effect.IO

val boom: IO[Int] = IO(throw new RuntimeException("fail"))
// Creating boom does NOT throw; running it would

Plain Scala Comparison

Without an effect type, side effects run immediately and are hard to compose. IO defers them, so a self-contained Scala program prints eagerly while IO would defer.

object Main {
  def main(args: Array[String]): Unit = {
    val eager = println("runs now") // executed immediately
    println("second line")
  }
}

Why Use IO?

IO gives you:

  • Purity — effects are values
  • Composability — build programs from small pieces
  • Safety — errors and resources are tracked
  • Concurrency — lightweight fibers

Quick Check

When does the side effect inside IO(println("hi")) actually execute?

Recap

The IO monad models effects as pure, lazy values:

  • IO(...) / IO.delay defer effects
  • IO.pure wraps computed values
  • IOApp / IOApp.Simple run programs
  • Exceptions are captured, not thrown eagerly

Next: composing multiple IO actions together.

Frequently asked questions

Is the “The IO Monad” lesson free?

Yes — the full text of “The IO Monad” is free to read here on the web, and the Scala for Backend Engineering & Functional Programming course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Scala for Backend Engineering & Functional Programming course, upgrade to CoddyKit PRO.

What will I learn in “The IO Monad”?

Pure effects. You practise Scala for Backend Engineering & Functional Programming with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Scala for Backend Engineering & Functional Programming?

No prior experience is required. Scala for Backend Engineering & Functional Programming on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “The IO Monad” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Scala for Backend Engineering & Functional Programming lesson?

Yes. Every Scala for Backend Engineering & Functional Programming lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Cats Type Classes
  2. The IO Monad
  3. Composing IO
  4. Error Handling in IO
← Back to Scala for Backend Engineering & Functional Programming