Skip to content

Glossary

Effect has its own vocabulary, and many of these words show up across every section of the docs. This page defines the terms you will meet most often, with a short, runnable example where one helps. Each entry links to the section that covers the concept in depth.

The example below threads several of these terms together — a service, a layer, an effect, a fiber, and a scope — so you can see how they relate before reading the individual definitions.

import { Context, Effect, Fiber, Layer } from "effect"
// A *service*: a class extending Context.Service<Self, Shape>()(id).
class AppClock extends Context.Service<AppClock, {
readonly now: Effect.Effect<number>
}>()("app/AppClock") {}
// A *layer*: a recipe that constructs the AppClock service.
const AppClockLayer = Layer.succeed(AppClock, { now: Effect.succeed(0) })
// An *effect*: a lazy description of work that needs an AppClock and yields a number.
const program = Effect.gen(function*() {
const clock = yield* AppClock // requirement on AppClock enters the R channel
// *forkChild* starts a *fiber* — a lightweight concurrent thread of execution.
const fiber = yield* Effect.forkChild(clock.now)
// A fiber is a plain value in v4; await it with Fiber.join.
return yield* Fiber.join(fiber)
})
// Providing the layer discharges the requirement; runPromise executes it.
program.pipe(Effect.provide(AppClockLayer), Effect.runPromise)

The central type, written Effect<A, E, R>. It is a lazy, immutable description of a computation that, when run, may:

  • succeed with a value of type A,
  • fail with an expected error of type E, or
  • require services of type R from its environment.

An Effect does nothing until it is run by a runtime. See Effect Essentials.

The three type parameters of Effect<A, E, R> are often called channels. The success channel (A) carries the result, the error channel (E) carries recoverable, typed failures, and the requirements channel (R) tracks which services the effect still needs. Providing those services empties the R channel; recovering from failures empties or narrows the E channel.

A fiber is a lightweight, virtual thread of execution — the unit of concurrency in Effect. Forking an effect (Effect.forkChild, Effect.forkDetach) starts a new fiber that runs concurrently with its parent. Fibers are cheap, interruptible, and scheduled cooperatively. In v4 a Fiber is a plain value: await it with Fiber.join or Fiber.await. See Concurrency.

The cooperative cancellation of a running fiber. When a fiber is interrupted, it stops at the next yield point and runs its finalizers so resources are released cleanly. Interruption is how Effect implements timeouts, racing, and structured shutdown without leaking resources. See Concurrency.

A service is a capability your effects depend on — a database client, an HTTP client, a clock. In v4 a service is defined as a class extending Context.Service<Self, Shape>()(identifier). Yielding the class inside a generator both retrieves the implementation and records the dependency in the effect’s requirements (R) channel. See Services & Layers.

The immutable, type-indexed map from service identifiers to their implementations, written Context<R>. It is the value that satisfies an effect’s requirements channel. You rarely build a Context by hand — a layer produces one for you.

A Context.Reference is a service that ships with a default value, so it can be read without being explicitly provided. References hold fiber-local configuration such as the current log level or concurrency limit (the built-in ones live on the References module), replacing v3’s FiberRef. Override a reference for a scope with Effect.provideService. See Runtime.

A layer, Layer<ROut, E, RIn>, is a recipe for constructing services. It describes how to build the services it outputs (ROut), what it might fail with (E), and which services it itself needs (RIn). Layers compose (Layer.provide, Layer.merge), are memoized so a shared dependency is built once, and handle acquisition and release of resources. See Services & Layers.

A scope is a container for finalizers. Resources acquired within a scope are released — in reverse order — when the scope closes, whether the effect succeeds, fails, or is interrupted. Scopes are how Effect guarantees cleanup; Effect.scoped runs an effect and closes its scope on completion. See Resource Management.

A Cause<E> is the full, structured explanation of why an effect did not succeed. Unlike a bare error value, it captures everything that went wrong. In v4 a Cause is a flat array of reasons, each one of:

  • Fail — an expected, typed error (the E channel),
  • Die — an unexpected defect (a thrown exception, a broken invariant),
  • Interrupt — the fiber was cancelled.

See Error Management.

A defect is an unexpected, unrecoverable failure that is not part of an effect’s typed error channel — for example a thrown exception or a violated invariant. Defects surface as Die reasons inside a cause. Use Effect.catchDefect only at boundaries; most code should let defects propagate.

An Exit<A, E> is the result of running an effect to completion. It is either a Success carrying a value of type A, or a Failure carrying a Cause<E>. Exit is what you inspect when you need to know exactly how an effect finished. See Runtime.

A Result<A, E> is a synchronous, value-level container that is either a success (Result.succeed) or a failure (Result.fail). It replaces v3’s Either and is what several Effect APIs return when they want to hand you a failure as data rather than via the error channel. See Data Types.

A Schema<Type, Encoded> describes a value’s shape and the transformation between its decoded (Type) and encoded (Encoded) forms. From one schema you get a decoder, an encoder, a type guard, and more — used for validation, parsing, and serialization at the edges of your program. See Schema.

A Stream<A, E, R> is the effectful, pull-based counterpart to Effect: it produces zero or more values of type A over time, may fail with E, and requires R. Streams are lazy, back-pressured, and composable, suitable for files, sockets, and other unbounded sources. See Streaming.

A Schedule is a reusable, composable description of a recurrence pattern — how many times and at what intervals to repeat or retry an effect (fixed delay, exponential backoff, jitter, and so on). The same schedule drives both Effect.repeat and Effect.retry. See Scheduling.

Effect.gen(function*() { ... }) is the imperative syntax for composing effects. Inside the generator, yield* runs an effect and binds its success value, so sequential effectful code reads like ordinary synchronous code while remaining fully typed and interruptible. See Effect Essentials.

A Yieldable is any type that can be yield*-ed inside an Effect.gen generator — Effect itself, plus Option, Result, Config, and service classes. In v4 being Yieldable is narrower than being an Effect: a yieldable value works in a generator but is not assignable to Effect elsewhere; convert it explicitly with Effect.fromOption / Effect.fromResult (or yield* it inside a generator) when a combinator needs an Effect.

pipe threads a value through a sequence of functions left to right, and most Effect combinators have a data-last (curried) form designed for it: effect.pipe(Effect.map(f), Effect.flatMap(g)). The data-last form keeps long transformation chains readable. See Code Style.

A typed error class carrying a literal _tag discriminant, defined with Schema.TaggedErrorClass. The tag lets Effect.catchTag / catchTags recover from one specific error among several in the error channel, with full type narrowing. See Error Management.