Concurrency
Effect is a concurrent framework powered by fibers — lightweight, virtual threads scheduled cooperatively by the Effect runtime. Because JavaScript is single-threaded, fibers don’t give you parallel CPU execution, but they do give you something more valuable: thousands of independent, cancellable units of work that interleave safely on a single thread, with first-class interruption and resource cleanup.
The defining property of concurrency in Effect is that it is structured. A
fiber you fork is a child of the fiber that forked it. When the parent
finishes, is interrupted, or fails, its children are interrupted too and their
finalizers run. You never leak a background task by accident, and you never have
to manually track every fiber you started — the runtime does it for you, the
same way a try/finally block scopes a resource.
import { Effect, Fiber } from "effect"
const program = Effect.gen(function*() { // Fork a child fiber. It is automatically supervised by this fiber: // if `program` finishes or is interrupted, the child is interrupted too. const fiber = yield* Effect.forkChild( Effect.sleep("1 second").pipe(Effect.as("done")) )
// Wait for the child's result, re-raising its failure into this fiber. const result = yield* Fiber.join(fiber) yield* Effect.log(result)})
Effect.runFork(program)What’s in this section
Section titled “What’s in this section”- Fibers — fork an effect into a child fiber, then
join,await, orinterruptit. Covers the supervised / scoped / detached fork strategies that determine a fiber’s lifetime. - Concurrency options — the
concurrencyoption onEffect.forEach,Effect.all, and friends, for running a collection of effects with a bounded or unbounded degree of parallelism. - Interruption — how Effect cancels work
safely: the asynchronous interruption model,
uninterruptibleregions, andonInterruptcleanup. - Racing and timeouts —
race,raceAll,raceFirst, andtimeoutfor “first one wins” semantics. - Semaphore and Latch — limit how many
fibers run at once with a
Semaphore; gate fibers until a condition is met with aLatch. - Fiber collections — supervise many
fibers with
FiberHandle,FiberMap, andFiberSet. - Queue and PubSub —
Queuefor distributing work among consumers;PubSubfor fanning a message out to every subscriber.
Where fibers come from
Section titled “Where fibers come from”You rarely create the runtime that runs fibers yourself. An effect runs inside a
fiber the moment you hand it to a runner like Effect.runFork,
Effect.runPromise, or a platform entrypoint such as NodeRuntime.runMain (see
Runtime). From there, concurrency comes from a small set of tools:
- Forking an effect with
Effect.forkChild(and its variants) starts a new fiber explicitly. - Concurrency options on combinators like
Effect.forEachfork a fiber per element behind the scenes. - Racing and timeouts fork competitors and interrupt the losers.
Everything else in this section — semaphores, latches, queues, pubsubs, and the fiber collections — exists to coordinate those fibers safely.