Documentation Index
Fetch the complete documentation index at: https://mintlify.com/effect-TS/effect-smol/llms.txt
Use this file to discover all available pages before exploring further.
This module provides utilities for working with Deferred, a powerful concurrency primitive that represents an asynchronous variable that can be set exactly once. Multiple fibers can await the same Deferred and will all be notified when it completes.
Overview
A Deferred<A, E> is like a promise that can be:
- Completed successfully with a value of type
A
- Failed with an error of type
E
- Interrupted if the fiber setting it is interrupted
Key characteristics:
- Single assignment: Can only be completed once
- Multiple waiters: Many fibers can await the same
Deferred
- Fiber-safe: Thread-safe operations across concurrent fibers
- Composable: Works seamlessly with other Effect operations
Basic Usage
import { Deferred, Effect, Fiber } from "effect"
// Coordinate between fibers
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<string, never>()
// Fiber 1: waits for the value
const waiter = yield* Effect.forkChild(
Effect.gen(function*() {
const value = yield* Deferred.await(deferred)
console.log("Received:", value)
return value
})
)
// Fiber 2: sets the value after a delay
const setter = yield* Effect.forkChild(
Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Deferred.succeed(deferred, "Hello from setter!")
})
)
yield* Fiber.join(waiter)
yield* Fiber.join(setter)
})
Types
Deferred
interface Deferred<in out A, in out E = never>
An asynchronous variable that can be set exactly once. Multiple fibers can suspend waiting for the value.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
// Create a Deferred that will hold a string value
const deferred: Deferred.Deferred<string> = yield* Deferred.make<string>()
yield* Deferred.succeed(deferred, "Hello, World!")
const value = yield* Deferred.await(deferred)
console.log(value) // "Hello, World!"
})
Creating Deferreds
make
const make: <A, E = never>() => Effect<Deferred<A, E>>
Creates a new Deferred.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.succeed(deferred, 42)
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
makeUnsafe
const makeUnsafe: <A, E = never>() => Deferred<A, E>
Unsafely creates a new Deferred without Effect wrapping.
import { Deferred } from "effect"
const deferred = Deferred.makeUnsafe<number>()
console.log(deferred)
Awaiting Values
await
const await: <A, E>(self: Deferred<A, E>) => Effect<A, E>
Retrieves the value of the Deferred, suspending the fiber until the result is available.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.succeed(deferred, 42)
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
Completing Deferreds
succeed
const succeed: {
<A>(value: A): <E>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, value: A): Effect<boolean>
}
Completes the Deferred with the specified value. Returns false if already completed.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.succeed(deferred, 42)
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
sync
const sync: {
<A>(evaluate: LazyArg<A>): <E>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<A>): Effect<boolean>
}
Completes the Deferred with a lazily evaluated value.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.sync(deferred, () => 42)
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
complete
const complete: {
<A, E, R>(effect: Effect<A, E, R>): (self: Deferred<A, E>) => Effect<boolean, never, R>
<A, E, R>(self: Deferred<A, E>, effect: Effect<A, E, R>): Effect<boolean, never, R>
}
Completes the deferred with the result of an effect. The result is memoized.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const completed = yield* Deferred.complete(deferred, Effect.succeed(42))
console.log(completed) // true
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
completeWith
const completeWith: {
<A, E>(effect: Effect<A, E>): (self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, effect: Effect<A, E>): Effect<boolean>
}
Completes the deferred with an effect (not memoized).
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const completed = yield* Deferred.completeWith(deferred, Effect.succeed(42))
console.log(completed) // true
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
Failing Deferreds
fail
const fail: {
<E>(error: E): <A>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, error: E): Effect<boolean>
}
Fails the Deferred with the specified error.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.fail(deferred, "Operation failed")
console.log(success) // true
})
failSync
const failSync: {
<E>(evaluate: LazyArg<E>): <A>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<E>): Effect<boolean>
}
Fails the Deferred with a lazily evaluated error.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.failSync(deferred, () => "Lazy error")
console.log(success) // true
})
failCause
const failCause: {
<E>(cause: Cause<E>): <A>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, cause: Cause<E>): Effect<boolean>
}
Fails the Deferred with the specified Cause.
import { Cause, Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.failCause(
deferred,
Cause.fail("Operation failed")
)
console.log(success) // true
})
failCauseSync
const failCauseSync: {
<E>(evaluate: LazyArg<Cause<E>>): <A>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<Cause<E>>): Effect<boolean>
}
Fails the Deferred with a lazily evaluated Cause.
import { Cause, Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const success = yield* Deferred.failCauseSync(
deferred,
() => Cause.fail("Lazy error")
)
console.log(success) // true
})
Killing Deferreds
die
const die: {
(defect: unknown): <A, E>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, defect: unknown): Effect<boolean>
}
Kills the Deferred with the specified defect.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.die(
deferred,
new Error("Something went wrong")
)
console.log(success) // true
})
dieSync
const dieSync: {
(evaluate: LazyArg<unknown>): <A, E>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, evaluate: LazyArg<unknown>): Effect<boolean>
}
Kills the Deferred with a lazily evaluated defect.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.dieSync(
deferred,
() => new Error("Lazy error")
)
console.log(success) // true
})
Interrupting Deferreds
interrupt
const interrupt: <A, E>(self: Deferred<A, E>) => Effect<boolean>
Completes the Deferred with interruption. This will interrupt all fibers waiting on the value.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.interrupt(deferred)
console.log(success) // true
})
interruptWith
const interruptWith: {
(fiberId: number): <A, E>(self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, fiberId: number): Effect<boolean>
}
Completes the Deferred with interruption using the specified FiberId.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const success = yield* Deferred.interruptWith(deferred, 42)
console.log(success) // true
})
Completion Status
done
const done: {
<A, E>(exit: Exit<A, E>): (self: Deferred<A, E>) => Effect<boolean>
<A, E>(self: Deferred<A, E>, exit: Exit<A, E>): Effect<boolean>
}
Exits the Deferred with the specified Exit value.
import { Deferred, Effect, Exit } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
yield* Deferred.done(deferred, Exit.succeed(42))
const value = yield* Deferred.await(deferred)
console.log(value) // 42
})
isDone
const isDone: <A, E>(self: Deferred<A, E>) => Effect<boolean>
Returns true if the Deferred has already been completed.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const beforeCompletion = yield* Deferred.isDone(deferred)
console.log(beforeCompletion) // false
yield* Deferred.succeed(deferred, 42)
const afterCompletion = yield* Deferred.isDone(deferred)
console.log(afterCompletion) // true
})
isDoneUnsafe
const isDoneUnsafe: <A, E>(self: Deferred<A, E>) => boolean
Unsafely checks if the Deferred has been completed.
poll
function poll<A, E>(self: Deferred<A, E>): Effect<Effect<A, E> | undefined>
Returns an Effect if the Deferred has already been completed, undefined otherwise.
import { Deferred, Effect } from "effect"
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number>()
const beforeCompletion = yield* Deferred.poll(deferred)
console.log(beforeCompletion === undefined) // true
yield* Deferred.succeed(deferred, 42)
const afterCompletion = yield* Deferred.poll(deferred)
console.log(afterCompletion !== undefined) // true
})
Unsafe Operations
doneUnsafe
const doneUnsafe: <A, E>(self: Deferred<A, E>, effect: Effect<A, E>) => boolean
Unsafely exits the Deferred with the specified effect.
import { Deferred, Effect } from "effect"
const deferred = Deferred.makeUnsafe<number>()
const success = Deferred.doneUnsafe(deferred, Effect.succeed(42))
console.log(success) // true
Integration with Effects
into
const into: {
<A, E>(deferred: Deferred<A, E>): <R>(self: Effect<A, E, R>) => Effect<boolean, never, R>
<A, E, R>(self: Effect<A, E, R>, deferred: Deferred<A, E>): Effect<boolean, never, R>
}
Converts an Effect into an operation that completes a Deferred with its result.
import { Deferred, Effect } from "effect"
const successEffect = Effect.succeed(42)
const program = Effect.gen(function*() {
const deferred = yield* Deferred.make<number, string>()
const isCompleted = yield* Deferred.into(successEffect, deferred)
const value = yield* Deferred.await(deferred)
console.log(value) // 42
return isCompleted // true
})
Common Patterns
Producer-Consumer
import { Deferred, Effect } from "effect"
const producerConsumer = Effect.gen(function*() {
const buffer = yield* Deferred.make<Array<number>, never>()
const producer = Effect.gen(function*() {
const data = [1, 2, 3, 4, 5]
yield* Deferred.succeed(buffer, data)
})
const consumer = Effect.gen(function*() {
const data = yield* Deferred.await(buffer)
return data.reduce((sum, n) => sum + n, 0)
})
const [, result] = yield* Effect.all([producer, consumer])
return result // 15
})
Coordination Point
import { Deferred, Effect, Fiber } from "effect"
const coordinationExample = Effect.gen(function*() {
const checkpoint = yield* Deferred.make<void>()
// Multiple fibers wait for checkpoint
const worker1 = Effect.gen(function*() {
yield* Deferred.await(checkpoint)
console.log("Worker 1 proceeding")
})
const worker2 = Effect.gen(function*() {
yield* Deferred.await(checkpoint)
console.log("Worker 2 proceeding")
})
const fiber1 = yield* Effect.forkChild(worker1)
const fiber2 = yield* Effect.forkChild(worker2)
// Release all workers at once
yield* Effect.sleep("1 second")
yield* Deferred.succeed(checkpoint, undefined)
yield* Fiber.join(fiber1)
yield* Fiber.join(fiber2)
})