What this is
Contrary to most sources, this guide focuses less on how to use Effect and more on why it exists and how it works under the hood — down to the loop that runs your code.
It comes in two parts. Ideally read them in order.
What is Effect
The why. One small program — a web handler reading a user from a database — written twice, plain and with Effect. It walks through three things that get better: invisible errors, threaded dependencies, and async coloring — all of which follow from one idea.
Read Part 1 → PART 2How it works under the hood
The how. We rebuild a working version of Effect from scratch — six sections build
the runtime, a seventh uses it for a real program — showing that an Effect value
is just a data structure that a loop walks.
The one idea
A normal function's type tells you what it returns when everything goes right. It stays quiet about two things: how it can fail, and what it needs to run. Those silences turn into surprises — an exception you didn't expect, a dependency you forgot to wire up.
Effect puts all three in one type:
The smallest possible before/after — a function that can fail:
const divide = (a: number, b: number): number => {
if (b === 0) throw new Error("Cannot divide by zero")
return a / b
}
// type says `number`. it does not say "or throws".
// you only find the failure by reading the body.
import { Effect } from "effect"
const divide = (a: number, b: number): Effect.Effect<number, Error> =>
b === 0
? Effect.fail(new Error("Cannot divide by zero"))
: Effect.succeed(a / b)
// the caller sees it without reading the body,
// and the compiler makes sure they deal with it.