Skip to content

Logging

Logging is an important aspect of software development, especially for debugging and monitoring the behavior of your applications. In this section, we’ll explore Effect’s logging utilities and see how they compare to traditional logging methods.

Effect’s logging utilities provide several benefits over conventional logging approaches:

  1. Dynamic Log Level Control: With Effect’s logging, you have the ability to change the log level dynamically. This means you can control which log messages get displayed based on their severity. For example, you can configure your application to log only warnings or errors, which can be extremely helpful in production environments to reduce noise.

  2. Custom Logging Output: Effect’s logging utilities allow you to change how logs are handled. You can direct log messages to various destinations, such as a service or a file, using a custom logger. This flexibility ensures that logs are stored and processed in a way that best suits your application’s requirements.

  3. Fine-Grained Logging: Effect enables fine-grained control over logging on a per-part basis of your program. You can set different log levels for different parts of your application, tailoring the level of detail to each specific component. This can be invaluable for debugging and troubleshooting, as you can focus on the information that matters most.

  4. Environment-Based Logging: Effect’s logging utilities can be combined with deployment environments to achieve granular logging strategies. For instance, during development, you might choose to log everything at a trace level and above for detailed debugging. In contrast, your production version could be configured to log only errors or critical issues, minimizing the impact on performance and noise in production logs.

  5. Additional Features: Effect’s logging utilities come with additional features such as the ability to measure time spans, alter log levels on a per-effect basis, and integrate spans for performance monitoring.

The Effect.log function allows you to log a message at the default INFO level.

Example (Logging a Simple Message)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("Application started")
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message="Application started"
*/

The default logger in Effect adds several useful details to each log entry:

AnnotationDescription
timestampThe timestamp when the log message was generated.
levelThe log level at which the message is logged (e.g., INFO, ERROR).
fiberThe identifier of the fiber executing the program.
messageThe log message content, which can include multiple strings or values.
span(Optional) The duration of a span in milliseconds, providing insight into the timing of operations.

You can also log multiple messages at once.

Example (Logging Multiple Messages)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message1", "message2", "message3")
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message=message1 message=message2 message=message3
*/

For added context, you can also include one or more Cause instances in your logs, which provide detailed error information under an additional cause annotation:

Example (Logging with Causes)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Cause
Cause
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
(
"message1",
"message2",
import Cause
Cause
.
const die: (defect: unknown) => Cause.Cause<never>

Creates a Die cause from an unexpected error.

Details

This function wraps an unhandled or unknown defect (like a runtime crash) into a Cause. It's useful for capturing unforeseen issues in a structured way.

@seeisDie Check if a Cause contains a defect

@since2.0.0

die
("Oh no!"),
import Cause
Cause
.
const die: (defect: unknown) => Cause.Cause<never>

Creates a Die cause from an unexpected error.

Details

This function wraps an unhandled or unknown defect (like a runtime crash) into a Cause. It's useful for capturing unforeseen issues in a structured way.

@seeisDie Check if a Cause contains a defect

@since2.0.0

die
("Oh uh!")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
Error: Oh uh!"
*/

By default, DEBUG messages are not displayed. To enable DEBUG logs, you can adjust the logging configuration using Logger.withMinimumLogLevel, setting the minimum level to LogLevel.Debug.

Example (Enabling Debug Logs)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
,
import LogLevel
LogLevel
} from "effect"
const
const task1: Effect.Effect<void, never, never>
task1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("2 seconds")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("task1 done") // Log a debug message
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Logger
Logger
.
const withMinimumLogLevel: (level: LogLevel.LogLevel) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Sets the minimum log level for subsequent logging operations, allowing control over which log messages are displayed based on their severity.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

withMinimumLogLevel
(
import LogLevel
LogLevel
.
const Debug: LogLevel.LogLevel

@since2.0.0

@since2.0.0

Debug
)) // Enable DEBUG level
const
const task2: Effect.Effect<void, never, never>
task2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("1 second")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("task2 done") // This message won't be logged
})
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("start")
yield*
const task1: Effect.Effect<void, never, never>
task1
yield*
const task2: Effect.Effect<void, never, never>
task2
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("done")
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO message=start
timestamp=... level=DEBUG message="task1 done" <-- 2 seconds later
timestamp=... level=INFO message=done <-- 1 second later
*/

The INFO log level is displayed by default. This level is typically used for general application events or progress updates.

Example (Logging at the Info Level)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logInfo: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the INFO log level.

Details

This function logs messages at the INFO level, suitable for general application events or operational messages. INFO logs are shown by default and are commonly used for highlighting normal, non-error operations.

@since2.0.0

logInfo
("start")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("2 seconds")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("1 second")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logInfo: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the INFO log level.

Details

This function logs messages at the INFO level, suitable for general application events or operational messages. INFO logs are shown by default and are commonly used for highlighting normal, non-error operations.

@since2.0.0

logInfo
("done")
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO message=start
timestamp=... level=INFO message=done <-- 3 seconds later
*/

The WARN log level is displayed by default. This level is intended for potential issues or warnings that do not immediately disrupt the flow of the program but should be monitored.

Example (Logging at the Warning Level)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Either

@since2.0.0

@since2.0.0

Either
} from "effect"
const
const task: Effect.Effect<number, string, never>
task
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

Details

This function allows you to ignore the original value inside an effect and replace it with a constant value.

When to Use

It is useful when you no longer need the value produced by an effect but want to ensure that the effect completes successfully with a specific constant result instead. For instance, you can replace the value produced by a computation with a predefined value, ignoring what was calculated before.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
// Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
const
const program: Effect.Effect<number, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, number>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, number, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const either: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Either.Either<number, string>, never, never>

Encapsulates both success and failure of an Effect into an Either type.

Details

This function converts an effect that may fail into an effect that always succeeds, wrapping the outcome in an Either type. The result will be Either.Left if the effect fails, containing the recoverable error, or Either.Right if it succeeds, containing the result.

Using this function, you can handle recoverable errors explicitly without causing the effect to fail. This is particularly useful in scenarios where you want to chain effects and manage both success and failure in the same logical flow.

It's important to note that unrecoverable errors, often referred to as "defects," are still thrown and not captured within the Either type. Only failures that are explicitly represented as recoverable errors in the effect are encapsulated.

The resulting effect cannot fail directly because all recoverable failures are represented inside the Either type.

@seeoption for a version that uses Option instead.

@seeexit for a version that encapsulates both recoverable errors and defects in an Exit.

@example

import { Effect, Either, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = Effect.gen(function* () {
// ┌─── Either<string, HttpError | ValidationError>
// ▼
const failureOrSuccess = yield* Effect.either(program)
return Either.match(failureOrSuccess, {
onLeft: (error) => `Recovering from ${error._tag}`,
onRight: (value) => value // Do nothing in case of success
})
})

@since2.0.0

either
(
const task: Effect.Effect<number, string, never>
task
)
if (
import Either

@since2.0.0

@since2.0.0

Either
.
const isLeft: <number, string>(self: Either.Either<number, string>) => self is Either.Left<string, number>

Determine if a Either is a Left.

@paramself - The Either to check.

@example

import { Either } from "effect"
assert.deepStrictEqual(Either.isLeft(Either.right(1)), false)
assert.deepStrictEqual(Either.isLeft(Either.left("a")), true)

@since2.0.0

isLeft
(
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
)) {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logWarning: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the WARNING log level.

Details

This function logs messages at the WARNING level, suitable for highlighting potential issues that are not errors but may require attention. These messages indicate that something unexpected occurred or might lead to errors in the future.

@since2.0.0

logWarning
(
const failureOrSuccess: Either.Left<string, number>
failureOrSuccess
.
Left<string, number>.left: string
left
)
return 0
} else {
return
const failureOrSuccess: Either.Right<string, number>
failureOrSuccess
.
Right<string, number>.right: number
right
}
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, never>(effect: Effect.Effect<number, never, never>, options?: RunForkOptions) => RuntimeFiber<number, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<number, never, never>
program
)
/*
Output:
timestamp=... level=WARN fiber=#0 message="Oh uh!"
*/

The ERROR log level is displayed by default. These messages represent issues that need to be addressed.

Example (Logging at the Error Level)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Either

@since2.0.0

@since2.0.0

Either
} from "effect"
const
const task: Effect.Effect<number, string, never>
task
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

Details

This function allows you to ignore the original value inside an effect and replace it with a constant value.

When to Use

It is useful when you no longer need the value produced by an effect but want to ensure that the effect completes successfully with a specific constant result instead. For instance, you can replace the value produced by a computation with a predefined value, ignoring what was calculated before.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
// Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
const
const program: Effect.Effect<number, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, number>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, number, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const either: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Either.Either<number, string>, never, never>

Encapsulates both success and failure of an Effect into an Either type.

Details

This function converts an effect that may fail into an effect that always succeeds, wrapping the outcome in an Either type. The result will be Either.Left if the effect fails, containing the recoverable error, or Either.Right if it succeeds, containing the result.

Using this function, you can handle recoverable errors explicitly without causing the effect to fail. This is particularly useful in scenarios where you want to chain effects and manage both success and failure in the same logical flow.

It's important to note that unrecoverable errors, often referred to as "defects," are still thrown and not captured within the Either type. Only failures that are explicitly represented as recoverable errors in the effect are encapsulated.

The resulting effect cannot fail directly because all recoverable failures are represented inside the Either type.

@seeoption for a version that uses Option instead.

@seeexit for a version that encapsulates both recoverable errors and defects in an Exit.

@example

import { Effect, Either, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = Effect.gen(function* () {
// ┌─── Either<string, HttpError | ValidationError>
// ▼
const failureOrSuccess = yield* Effect.either(program)
return Either.match(failureOrSuccess, {
onLeft: (error) => `Recovering from ${error._tag}`,
onRight: (value) => value // Do nothing in case of success
})
})

@since2.0.0

either
(
const task: Effect.Effect<number, string, never>
task
)
if (
import Either

@since2.0.0

@since2.0.0

Either
.
const isLeft: <number, string>(self: Either.Either<number, string>) => self is Either.Left<string, number>

Determine if a Either is a Left.

@paramself - The Either to check.

@example

import { Either } from "effect"
assert.deepStrictEqual(Either.isLeft(Either.right(1)), false)
assert.deepStrictEqual(Either.isLeft(Either.left("a")), true)

@since2.0.0

isLeft
(
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
)) {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logError: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the ERROR log level.

Details

This function logs messages at the ERROR level, suitable for reporting application errors or failures. These logs are typically used for unexpected issues that need immediate attention.

@since2.0.0

logError
(
const failureOrSuccess: Either.Left<string, number>
failureOrSuccess
.
Left<string, number>.left: string
left
)
return 0
} else {
return
const failureOrSuccess: Either.Right<string, number>
failureOrSuccess
.
Right<string, number>.right: number
right
}
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, never>(effect: Effect.Effect<number, never, never>, options?: RunForkOptions) => RuntimeFiber<number, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<number, never, never>
program
)
/*
Output:
timestamp=... level=ERROR fiber=#0 message="Oh uh!"
*/

The FATAL log level is displayed by default. This log level is typically reserved for unrecoverable errors.

Example (Logging at the Fatal Level)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Either

@since2.0.0

@since2.0.0

Either
} from "effect"
const
const task: Effect.Effect<number, string, never>
task
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

@seesucceed to create an effect that represents a successful value.

@example

// Title: Creating a Failed Effect
import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@since2.0.0

fail
("Oh uh!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<number, string, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<number, string, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const as: <number>(value: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<number, E, R> (+1 overload)

Replaces the value inside an effect with a constant value.

Details

This function allows you to ignore the original value inside an effect and replace it with a constant value.

When to Use

It is useful when you no longer need the value produced by an effect but want to ensure that the effect completes successfully with a specific constant result instead. For instance, you can replace the value produced by a computation with a predefined value, ignoring what was calculated before.

@example

// Title: Replacing a Value
import { pipe, Effect } from "effect"
// Replaces the value 5 with the constant "new value"
const program = pipe(Effect.succeed(5), Effect.as("new value"))
// Effect.runPromise(program).then(console.log)
// Output: "new value"

@since2.0.0

as
(2))
const
const program: Effect.Effect<number, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, number>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, number, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
= yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const either: <number, string, never>(self: Effect.Effect<number, string, never>) => Effect.Effect<Either.Either<number, string>, never, never>

Encapsulates both success and failure of an Effect into an Either type.

Details

This function converts an effect that may fail into an effect that always succeeds, wrapping the outcome in an Either type. The result will be Either.Left if the effect fails, containing the recoverable error, or Either.Right if it succeeds, containing the result.

Using this function, you can handle recoverable errors explicitly without causing the effect to fail. This is particularly useful in scenarios where you want to chain effects and manage both success and failure in the same logical flow.

It's important to note that unrecoverable errors, often referred to as "defects," are still thrown and not captured within the Either type. Only failures that are explicitly represented as recoverable errors in the effect are encapsulated.

The resulting effect cannot fail directly because all recoverable failures are represented inside the Either type.

@seeoption for a version that uses Option instead.

@seeexit for a version that encapsulates both recoverable errors and defects in an Exit.

@example

import { Effect, Either, Random } from "effect"
class HttpError {
readonly _tag = "HttpError"
}
class ValidationError {
readonly _tag = "ValidationError"
}
// ┌─── Effect<string, HttpError | ValidationError, never>
// ▼
const program = Effect.gen(function* () {
const n1 = yield* Random.next
const n2 = yield* Random.next
if (n1 < 0.5) {
yield* Effect.fail(new HttpError())
}
if (n2 < 0.5) {
yield* Effect.fail(new ValidationError())
}
return "some result"
})
// ┌─── Effect<string, never, never>
// ▼
const recovered = Effect.gen(function* () {
// ┌─── Either<string, HttpError | ValidationError>
// ▼
const failureOrSuccess = yield* Effect.either(program)
return Either.match(failureOrSuccess, {
onLeft: (error) => `Recovering from ${error._tag}`,
onRight: (value) => value // Do nothing in case of success
})
})

@since2.0.0

either
(
const task: Effect.Effect<number, string, never>
task
)
if (
import Either

@since2.0.0

@since2.0.0

Either
.
const isLeft: <number, string>(self: Either.Either<number, string>) => self is Either.Left<string, number>

Determine if a Either is a Left.

@paramself - The Either to check.

@example

import { Either } from "effect"
assert.deepStrictEqual(Either.isLeft(Either.right(1)), false)
assert.deepStrictEqual(Either.isLeft(Either.left("a")), true)

@since2.0.0

isLeft
(
const failureOrSuccess: Either.Either<number, string>
failureOrSuccess
)) {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logFatal: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the FATAL log level.

Details

This function logs messages at the FATAL level, suitable for reporting critical errors that cause the application to terminate or stop functioning. These logs are typically used for unrecoverable errors that require immediate attention.

@since2.0.0

logFatal
(
const failureOrSuccess: Either.Left<string, number>
failureOrSuccess
.
Left<string, number>.left: string
left
)
return 0
} else {
return
const failureOrSuccess: Either.Right<string, number>
failureOrSuccess
.
Right<string, number>.right: number
right
}
})
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <number, never>(effect: Effect.Effect<number, never, never>, options?: RunForkOptions) => RuntimeFiber<number, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<number, never, never>
program
)
/*
Output:
timestamp=... level=FATAL fiber=#0 message="Oh uh!"
*/

You can enhance your log outputs by adding custom annotations using the Effect.annotateLogs function. This allows you to attach extra metadata to each log entry, making it easier to trace and add context to your logs.

Enhance your log outputs by incorporating custom annotations with the Effect.annotateLogs function. This function allows you to append additional metadata to each log entry of an effect, enhancing traceability and context.

You can apply a single annotation as a key/value pair to all log entries within an effect.

Example (Single Key/Value Annotation)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message1")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message2")
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
// Annotation as key/value pair
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (key: string, value: unknown) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
("key", "value")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message=message1 key=value
timestamp=... level=INFO fiber=#0 message=message2 key=value
*/

In this example, all logs generated within the program will include the annotation key=value.

Annotations propagate to all logs generated within nested or downstream effects. This ensures that logs from any child effects inherit the parent effect’s annotations.

Example (Propagating Annotations to Nested Effects)

In this example, the annotation key=value is included in all logs, even those from the nested anotherProgram effect.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// Define a child program that logs an error
const
const anotherProgram: Effect.Effect<void, never, never>
anotherProgram
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logError: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the ERROR log level.

Details

This function logs messages at the ERROR level, suitable for reporting application errors or failures. These logs are typically used for unexpected issues that need immediate attention.

@since2.0.0

logError
("error1")
})
// Define the main program
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message1")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message2")
yield*
const anotherProgram: Effect.Effect<void, never, never>
anotherProgram
// Call the nested program
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
// Attach an annotation to all logs in the scope
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (key: string, value: unknown) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
("key", "value")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message=message1 key=value
timestamp=... level=INFO fiber=#0 message=message2 key=value
timestamp=... level=ERROR fiber=#0 message=error1 key=value
*/

You can also apply multiple annotations at once by passing an object with key/value pairs. Each key/value pair will be added to every log entry within the effect.

Example (Multiple Annotations)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message1")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message2")
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
// Add multiple annotations
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
({
key1: string
key1
: "value1",
key2: string
key2
: "value2" })
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message=message1 key2=value2 key1=value1
timestamp=... level=INFO fiber=#0 message=message2 key2=value2 key1=value1
*/

In this case, each log will contain both key1=value1 and key2=value2.

If you want to limit the scope of your annotations so that they only apply to certain log entries, you can use Effect.annotateLogsScoped. This function confines the annotations to logs produced within a specific scope.

Example (Scoped Annotations)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, Scope>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, Scope>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("no annotations") // No annotations
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogsScoped: (values: Record<string, unknown>) => Effect.Effect<void, never, Scope> (+1 overload)

Adds log annotations with a limited scope to enhance contextual logging.

Details

This function allows you to apply key-value annotations to log entries generated within a specific scope of your effect computations. The annotations are restricted to the defined Scope, ensuring that they are only applied to logs produced during that scope. Once the scope ends, the annotations are automatically removed, making it easier to manage context-specific logging without affecting other parts of your application.

The annotations can be provided as a single key-value pair or as a record of multiple key-value pairs. This flexibility enables fine-grained control over the additional metadata included in logs for specific tasks or operations.

@seeannotateLogs to add custom annotations to log entries generated within an effect.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("no annotations")
yield* Effect.annotateLogsScoped({ key: "value" })
yield* Effect.log("message1") // Annotation is applied to this log
yield* Effect.log("message2") // Annotation is applied to this log
}).pipe(Effect.scoped, Effect.andThen(Effect.log("no annotations again")))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="no annotations"
// timestamp=... level=INFO fiber=#0 message=message1 key=value
// timestamp=... level=INFO fiber=#0 message=message2 key=value
// timestamp=... level=INFO fiber=#0 message="no annotations again"

@since3.1.0

annotateLogsScoped
({
key: string
key
: "value" }) // Scoped annotation
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message1") // Annotation applied
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("message2") // Annotation applied
}).
Pipeable.pipe<Effect.Effect<void, never, Scope>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, Scope>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const scoped: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Scope>>

Scopes all resources used in an effect to the lifetime of the effect.

Details

This function ensures that all resources used within an effect are tied to its lifetime. Finalizers for these resources are executed automatically when the effect completes, whether through success, failure, or interruption. This guarantees proper resource cleanup without requiring explicit management.

@since2.0.0

scoped
,
// Outside scope, no annotations
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <Effect.Effect<void, never, never>>(f: Effect.Effect<void, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R> (+3 overloads)

Chains two actions, where the second action can depend on the result of the first.

Syntax

const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect))
// or
const transformedEffect = Effect.andThen(myEffect, anotherEffect)
// or
const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect))

When to Use

Use andThen when you need to run multiple actions in sequence, with the second action depending on the result of the first. This is useful for combining effects or handling computations that must happen in order.

Details

The second action can be:

  • A constant value (similar to

as

)

  • A function returning a value (similar to

map

)

  • A Promise
  • A function returning a Promise
  • An Effect
  • A function returning an Effect (similar to

flatMap

)

Note: andThen works well with both Option and Either types, treating them as effects.

@example

// Title: Applying a Discount Based on Fetched Amount
import { pipe, Effect } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
// Using Effect.map and Effect.flatMap
const result1 = pipe(
fetchTransactionAmount,
Effect.map((amount) => amount * 2),
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
// Effect.runPromise(result1).then(console.log)
// Output: 190
// Using Effect.andThen
const result2 = pipe(
fetchTransactionAmount,
Effect.andThen((amount) => amount * 2),
Effect.andThen((amount) => applyDiscount(amount, 5))
)
// Effect.runPromise(result2).then(console.log)
// Output: 190

@since2.0.0

andThen
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("no annotations again"))
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message="no annotations"
timestamp=... level=INFO fiber=#0 message=message1 key=value
timestamp=... level=INFO fiber=#0 message=message2 key=value
timestamp=... level=INFO fiber=#0 message="no annotations again"
*/

Effect provides built-in support for log spans, which allow you to measure and log the duration of specific tasks or sections of your code. This feature is helpful for tracking how long certain operations take, giving you better insights into the performance of your application.

Example (Measuring Task Duration with a Log Span)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
// Simulate a delay to represent a task taking time
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("1 second")
// Log a message indicating the job is done
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("The job is finished!")
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
// Apply a log span labeled "myspan" to measure
// the duration of this operation
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("myspan")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms
*/

Sometimes, perhaps during test execution, you might want to disable default logging in your application. Effect provides several ways to turn off logging when needed. In this section, we’ll look at different methods to disable logging in the Effect framework.

Example (Using Logger.withMinimumLogLevel)

One convenient way to disable logging is by using the Logger.withMinimumLogLevel function. This allows you to set the minimum log level to None, effectively turning off all log output.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
,
import LogLevel
LogLevel
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("Executing task...")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("100 millis")
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("task done")
})
// Default behavior: logging enabled
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
timestamp=... level=INFO fiber=#0 message="Executing task..."
task done
*/
// Disable logging by setting minimum log level to 'None'
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Logger
Logger
.
const withMinimumLogLevel: (level: LogLevel.LogLevel) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Sets the minimum log level for subsequent logging operations, allowing control over which log messages are displayed based on their severity.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

withMinimumLogLevel
(
import LogLevel
LogLevel
.
const None: LogLevel.LogLevel

@since2.0.0

@since2.0.0

None
)))
/*
Output:
task done
*/

Example (Using a Layer)

Another approach to disable logging is by creating a layer that sets the minimum log level to LogLevel.None, effectively turning off all log output.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
,
import LogLevel
LogLevel
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("Executing task...")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("100 millis")
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("task done")
})
// Create a layer that disables logging
const
const layer: Layer<never, never, never>
layer
=
import Logger
Logger
.
const minimumLogLevel: (level: LogLevel.LogLevel) => Layer<never>

Sets the minimum log level for logging operations, allowing control over which log messages are displayed based on their severity.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("Executing task...")
yield* Effect.sleep("100 millis")
console.log("task done")
})
// Logging disabled using a layer
// Effect.runFork(program.pipe(Effect.provide(Logger.minimumLogLevel(LogLevel.None))))
// task done

@since2.0.0

minimumLogLevel
(
import LogLevel
LogLevel
.
const None: LogLevel.LogLevel

@since2.0.0

@since2.0.0

None
)
// Apply the layer to disable logging
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
const layer: Layer<never, never, never>
layer
)))
/*
Output:
task done
*/

Example (Using a Custom Runtime)

You can also disable logging by creating a custom runtime that includes the configuration to turn off logging:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
,
import LogLevel
LogLevel
,
import ManagedRuntime
ManagedRuntime
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("Executing task...")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("100 millis")
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("task done")
})
// Create a custom runtime that disables logging
const
const customRuntime: ManagedRuntime.ManagedRuntime<never, never>
customRuntime
=
import ManagedRuntime
ManagedRuntime
.
const make: <never, never>(layer: Layer<never, never, never>, memoMap?: MemoMap | undefined) => ManagedRuntime.ManagedRuntime<never, never>

Convert a Layer into an ManagedRuntime, that can be used to run Effect's using your services.

@since2.0.0

@example

import { Console, Effect, Layer, ManagedRuntime } from "effect"
class Notifications extends Effect.Tag("Notifications")<
Notifications,
{ readonly notify: (message: string) => Effect.Effect<void> }
>() {
static Live = Layer.succeed(this, { notify: (message) => Console.log(message) })
}
async function main() {
const runtime = ManagedRuntime.make(Notifications.Live)
await runtime.runPromise(Notifications.notify("Hello, world!"))
await runtime.dispose()
}
main()

make
(
import Logger
Logger
.
const minimumLogLevel: (level: LogLevel.LogLevel) => Layer<never>

Sets the minimum log level for logging operations, allowing control over which log messages are displayed based on their severity.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("Executing task...")
yield* Effect.sleep("100 millis")
console.log("task done")
})
// Logging disabled using a layer
// Effect.runFork(program.pipe(Effect.provide(Logger.minimumLogLevel(LogLevel.None))))
// task done

@since2.0.0

minimumLogLevel
(
import LogLevel
LogLevel
.
const None: LogLevel.LogLevel

@since2.0.0

@since2.0.0

None
)
)
// Run the program using the custom runtime
const customRuntime: ManagedRuntime.ManagedRuntime<never, never>
customRuntime
.
ManagedRuntime<never, never>.runFork: <void, never>(self: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Executes the effect using the provided Scheduler or using the global Scheduler if not provided

runFork
(
const program: Effect.Effect<void, never, never>
program
)
/*
Output:
task done
*/

To dynamically load the log level from a configuration and apply it to your program, you can use the Logger.minimumLogLevel layer. This allows your application to adjust its logging behavior based on external configuration.

Example (Loading Log Level from Configuration)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Config
Config
,
import Logger
Logger
,
import Layer
Layer
,
import ConfigProvider
ConfigProvider
,
import LogLevel
LogLevel
} from "effect"
// Simulate a program with logs
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logError: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the ERROR log level.

Details

This function logs messages at the ERROR level, suitable for reporting application errors or failures. These logs are typically used for unexpected issues that need immediate attention.

@since2.0.0

logError
("ERROR!")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logWarning: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the WARNING log level.

Details

This function logs messages at the WARNING level, suitable for highlighting potential issues that are not errors but may require attention. These messages indicate that something unexpected occurred or might lead to errors in the future.

@since2.0.0

logWarning
("WARNING!")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logInfo: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the INFO log level.

Details

This function logs messages at the INFO level, suitable for general application events or operational messages. INFO logs are shown by default and are commonly used for highlighting normal, non-error operations.

@since2.0.0

logInfo
("INFO!")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("DEBUG!")
})
// Load the log level from the configuration and apply it as a layer
const
const LogLevelLive: Layer.Layer<never, ConfigError, never>
LogLevelLive
=
import Config
Config
.
const logLevel: (name?: string) => Config.Config<LogLevel.LogLevel>

Constructs a config for a LogLevel value.

@since2.0.0

logLevel
("LOG_LEVEL").
Pipeable.pipe<Config.Config<LogLevel.LogLevel>, Effect.Effect<Layer.Layer<never, never, never>, ConfigError, never>, Layer.Layer<never, ConfigError, never>>(this: Config.Config<...>, ab: (_: Config.Config<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const andThen: <LogLevel.LogLevel, Layer.Layer<never, never, never>>(f: (a: LogLevel.LogLevel) => Layer.Layer<never, never, never>) => <E, R>(self: Effect.Effect<LogLevel.LogLevel, E, R>) => Effect.Effect<...> (+3 overloads)

Chains two actions, where the second action can depend on the result of the first.

Syntax

const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect))
// or
const transformedEffect = Effect.andThen(myEffect, anotherEffect)
// or
const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect))

When to Use

Use andThen when you need to run multiple actions in sequence, with the second action depending on the result of the first. This is useful for combining effects or handling computations that must happen in order.

Details

The second action can be:

  • A constant value (similar to

as

)

  • A function returning a value (similar to

map

)

  • A Promise
  • A function returning a Promise
  • An Effect
  • A function returning an Effect (similar to

flatMap

)

Note: andThen works well with both Option and Either types, treating them as effects.

@example

// Title: Applying a Discount Based on Fetched Amount
import { pipe, Effect } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
// Using Effect.map and Effect.flatMap
const result1 = pipe(
fetchTransactionAmount,
Effect.map((amount) => amount * 2),
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
// Effect.runPromise(result1).then(console.log)
// Output: 190
// Using Effect.andThen
const result2 = pipe(
fetchTransactionAmount,
Effect.andThen((amount) => amount * 2),
Effect.andThen((amount) => applyDiscount(amount, 5))
)
// Effect.runPromise(result2).then(console.log)
// Output: 190

@since2.0.0

andThen
((
level: LogLevel.LogLevel
level
) =>
// Set the minimum log level
import Logger
Logger
.
const minimumLogLevel: (level: LogLevel.LogLevel) => Layer.Layer<never>

Sets the minimum log level for logging operations, allowing control over which log messages are displayed based on their severity.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("Executing task...")
yield* Effect.sleep("100 millis")
console.log("task done")
})
// Logging disabled using a layer
// Effect.runFork(program.pipe(Effect.provide(Logger.minimumLogLevel(LogLevel.None))))
// task done

@since2.0.0

minimumLogLevel
(
level: LogLevel.LogLevel
level
)
),
import Layer
Layer
.
const unwrapEffect: <A, E1, R1, E, R>(self: Effect.Effect<Layer.Layer<A, E1, R1>, E, R>) => Layer.Layer<A, E | E1, R | R1>

@since2.0.0

unwrapEffect
// Convert the effect into a layer
)
// Provide the loaded log level to the program
const
const configured: Effect.Effect<void, ConfigError, never>
configured
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <void, never, never, never, ConfigError, never>(self: Effect.Effect<void, never, never>, layer: Layer.Layer<never, ConfigError, never>) => Effect.Effect<...> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
const program: Effect.Effect<void, never, never>
program
,
const LogLevelLive: Layer.Layer<never, ConfigError, never>
LogLevelLive
)
// Test the program using a mock configuration provider
const
const test: Effect.Effect<void, ConfigError, never>
test
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <void, ConfigError, never, never, never, never>(self: Effect.Effect<void, ConfigError, never>, layer: Layer.Layer<never, never, never>) => Effect.Effect<...> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
const configured: Effect.Effect<void, ConfigError, never>
configured
,
import Layer
Layer
.
const setConfigProvider: (configProvider: ConfigProvider.ConfigProvider) => Layer.Layer<never>

Sets the current ConfigProvider.

@since2.0.0

setConfigProvider
(
import ConfigProvider
ConfigProvider
.
const fromMap: (map: Map<string, string>, config?: Partial<ConfigProvider.ConfigProvider.FromMapConfig>) => ConfigProvider.ConfigProvider

Constructs a ConfigProvider using a map and the specified delimiter string, which determines how to split the keys in the map into path segments.

@since2.0.0

fromMap
(
new
var Map: MapConstructor
new <string, "ALL" | "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" | "OFF">(iterable?: Iterable<readonly [string, "ALL" | "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" | "OFF"]> | null | undefined) => Map<...> (+3 overloads)
Map
([["LOG_LEVEL",
import LogLevel
LogLevel
.
const Warning: LogLevel.LogLevel

@since2.0.0

@since2.0.0

Warning
.
label: "ALL" | "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" | "OFF"
label
]])
)
)
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: RunForkOptions) => RuntimeFiber<...>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const test: Effect.Effect<void, ConfigError, never>
test
)
/*
Output:
... level=ERROR fiber=#0 message=ERROR!
... level=WARN fiber=#0 message=WARNING!
*/

In this section, you’ll learn how to define a custom logger and set it as the default logger in your application. Custom loggers give you control over how log messages are handled, such as routing them to external services, writing to files, or formatting logs in a specific way.

You can define your own logger using the Logger.make function. This function allows you to specify how log messages should be processed.

Example (Defining a Simple Custom Logger)

import {
import Logger
Logger
} from "effect"
// Custom logger that outputs log messages to the console
const
const logger: Logger.Logger<unknown, void>
logger
=
import Logger
Logger
.
const make: <unknown, void>(log: (options: Logger.Logger<in Message, out Output>.Options<unknown>) => void) => Logger.Logger<unknown, void>

Creates a custom logger that formats log messages according to the provided function.

@example

import { Effect, Logger, LogLevel } from "effect"
const logger = Logger.make(({ logLevel, message }) => {
globalThis.console.log(`[${logLevel.label}] ${message}`)
})
const task1 = Effect.logDebug("task1 done")
const task2 = Effect.logDebug("task2 done")
const program = Effect.gen(function*() {
yield* Effect.log("start")
yield* task1
yield* task2
yield* Effect.log("done")
}).pipe(
Logger.withMinimumLogLevel(LogLevel.Debug),
Effect.provide(Logger.replace(Logger.defaultLogger, logger))
)
// Effect.runFork(program)
// [INFO] start
// [DEBUG] task1 done
// [DEBUG] task2 done
// [INFO] done

@since2.0.0

make
(({
logLevel: LogLevel
logLevel
,
message: unknown
message
}) => {
module globalThis
globalThis
.
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(`[${
logLevel: LogLevel
logLevel
.
label: "ALL" | "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" | "OFF"
label
}] ${
message: unknown
message
}`)
})

In this example, the custom logger logs messages to the console with the log level and message formatted as [LogLevel] Message.

Let’s assume you have the following tasks and a program where you log some messages:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
} from "effect"
4 collapsed lines
// Custom logger that outputs log messages to the console
const
const logger: Logger.Logger<unknown, void>
logger
=
import Logger
Logger
.
const make: <unknown, void>(log: (options: Logger.Logger<in Message, out Output>.Options<unknown>) => void) => Logger.Logger<unknown, void>

Creates a custom logger that formats log messages according to the provided function.

@example

import { Effect, Logger, LogLevel } from "effect"
const logger = Logger.make(({ logLevel, message }) => {
globalThis.console.log(`[${logLevel.label}] ${message}`)
})
const task1 = Effect.logDebug("task1 done")
const task2 = Effect.logDebug("task2 done")
const program = Effect.gen(function*() {
yield* Effect.log("start")
yield* task1
yield* task2
yield* Effect.log("done")
}).pipe(
Logger.withMinimumLogLevel(LogLevel.Debug),
Effect.provide(Logger.replace(Logger.defaultLogger, logger))
)
// Effect.runFork(program)
// [INFO] start
// [DEBUG] task1 done
// [DEBUG] task2 done
// [INFO] done

@since2.0.0

make
(({
logLevel: LogLevel
logLevel
,
message: unknown
message
}) => {
module globalThis
globalThis
.
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(`[${
logLevel: LogLevel
logLevel
.
label: "ALL" | "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" | "OFF"
label
}] ${
message: unknown
message
}`)
})
const
const task1: Effect.Effect<void, never, never>
task1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("2 seconds")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("task1 done")
})
const
const task2: Effect.Effect<void, never, never>
task2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("1 second")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("task2 done")
})
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("start")
yield*
const task1: Effect.Effect<void, never, never>
task1
yield*
const task2: Effect.Effect<void, never, never>
task2
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("done")
})

To replace the default logger with your custom logger, you can use the Logger.replace function. After creating a layer that replaces the default logger, you provide it to your program using Effect.provide.

Example (Replacing the Default Logger with a Custom Logger)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
,
import LogLevel
LogLevel
} from "effect"
21 collapsed lines
// Custom logger that outputs log messages to the console
const
const logger: Logger.Logger<unknown, void>
logger
=
import Logger
Logger
.
const make: <unknown, void>(log: (options: Logger.Logger<in Message, out Output>.Options<unknown>) => void) => Logger.Logger<unknown, void>

Creates a custom logger that formats log messages according to the provided function.

@example

import { Effect, Logger, LogLevel } from "effect"
const logger = Logger.make(({ logLevel, message }) => {
globalThis.console.log(`[${logLevel.label}] ${message}`)
})
const task1 = Effect.logDebug("task1 done")
const task2 = Effect.logDebug("task2 done")
const program = Effect.gen(function*() {
yield* Effect.log("start")
yield* task1
yield* task2
yield* Effect.log("done")
}).pipe(
Logger.withMinimumLogLevel(LogLevel.Debug),
Effect.provide(Logger.replace(Logger.defaultLogger, logger))
)
// Effect.runFork(program)
// [INFO] start
// [DEBUG] task1 done
// [DEBUG] task2 done
// [INFO] done

@since2.0.0

make
(({
logLevel: LogLevel.LogLevel
logLevel
,
message: unknown
message
}) => {
module globalThis
globalThis
.
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(`[${
logLevel: LogLevel.LogLevel
logLevel
.
label: "ALL" | "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE" | "OFF"
label
}] ${
message: unknown
message
}`)
})
const
const task1: Effect.Effect<void, never, never>
task1
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("2 seconds")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("task1 done")
})
const
const task2: Effect.Effect<void, never, never>
task2
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
// Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("1 second")
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs messages at the DEBUG log level.

Details

This function logs messages at the DEBUG level, which is typically used for diagnosing application behavior during development. DEBUG messages provide less detailed information than TRACE logs but are still not shown by default. To view these logs, adjust the log level using Logger.withMinimumLogLevel.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

logDebug
("task2 done")
})
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

@example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("start")
yield*
const task1: Effect.Effect<void, never, never>
task1
yield*
const task2: Effect.Effect<void, never, never>
task2
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("done")
})
// Replace the default logger with the custom logger
const
const layer: Layer<never, never, never>
layer
=
import Logger
Logger
.
const replace: <void, void>(self: Logger.Logger<unknown, void>, that: Logger.Logger<unknown, void>) => Layer<never> (+1 overload)

@since2.0.0

replace
(
import Logger
Logger
.
const defaultLogger: Logger.Logger<unknown, void>

@since2.0.0

defaultLogger
,
const logger: Logger.Logger<unknown, void>
logger
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Logger
Logger
.
const withMinimumLogLevel: (level: LogLevel.LogLevel) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Sets the minimum log level for subsequent logging operations, allowing control over which log messages are displayed based on their severity.

@example

import { Effect, Logger, LogLevel } from "effect"
const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug))
// Effect.runFork(program)
// timestamp=... level=DEBUG fiber=#0 message=message1

@since2.0.0

withMinimumLogLevel
(
import LogLevel
LogLevel
.
const Debug: LogLevel.LogLevel

@since2.0.0

@since2.0.0

Debug
),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
const layer: Layer<never, never, never>
layer
)
)
)

When you run the above program, the following log messages are printed to the console:

Terminal window
[INFO] start
[DEBUG] task1 done
[DEBUG] task2 done
[INFO] done

Effect provides several built-in loggers that you can use depending on your logging needs. These loggers offer different formats, each suited for different environments or purposes, such as development, production, or integration with external logging services.

Each logger is available in two forms: the logger itself, and a layer that uses the logger and sends its output to the Console default service. For example, the structuredLogger logger generates logs in a detailed object-based format, while the structured layer uses the same logger and writes the output to the Console service.

The stringLogger logger produces logs in a human-readable key-value style. This format is commonly used in development and production because it is simple and easy to read in the console.

This logger does not have a corresponding layer because it is the default logger.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("msg1", "msg2", ["msg3", "msg4"]).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

@example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
// Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
({
key1: string
key1
: "value1",
key2: string
key2
: "value2" }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("myspan")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
)

Output:

Terminal window
timestamp=2024-12-28T10:44:31.281Z level=INFO fiber=#0 message=msg1 message=msg2 message="[
\"msg3\",
\"msg4\"
]" myspan=102ms key2=value2 key1=value1

The logfmtLogger logger produces logs in a human-readable key-value format, similar to the stringLogger logger. The main difference is that logfmtLogger removes extra spaces to make logs more compact.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("msg1", "msg2", ["msg3", "msg4"]).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

@example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
// Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
({
key1: string
key1
: "value1",
key2: string
key2
: "value2" }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("myspan")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import Logger
Logger
.
const logFmt: Layer<never, never, never>

This logger outputs logs in a human-readable format that is easy to read during development or in a production console.

@example

import { Effect, Logger } from "effect"
const program = Effect.log("message1", "message2").pipe(
Effect.annotateLogs({ key1: "value1", key2: "value2" }),
Effect.withLogSpan("myspan")
)
// Effect.runFork(program.pipe(Effect.provide(Logger.logFmt)))
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 myspan=0ms key2=value2 key1=value1

@since2.0.0

logFmt
)))

Output:

Terminal window
timestamp=2024-12-28T10:44:31.281Z level=INFO fiber=#0 message=msg1 message=msg2 message="[\"msg3\",\"msg4\"]" myspan=102ms key2=value2 key1=value1

The prettyLogger logger enhances log output by using color and indentation for better readability, making it particularly useful during development when visually scanning logs in the console.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("msg1", "msg2", ["msg3", "msg4"]).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

@example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
// Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
({
key1: string
key1
: "value1",
key2: string
key2
: "value2" }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("myspan")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import Logger
Logger
.
const pretty: Layer<never, never, never>

The pretty logger utilizes the capabilities of the console API to generate visually engaging and color-enhanced log outputs. This feature is particularly useful for improving the readability of log messages during development and debugging processes.

@example

import { Effect, Logger } from "effect"
const program = Effect.log("message1", "message2").pipe(
Effect.annotateLogs({ key1: "value1", key2: "value2" }),
Effect.withLogSpan("myspan")
)
// Effect.runFork(program.pipe(Effect.provide(Logger.pretty)))
// green --v v-- bold and cyan
// [07:51:54.434] INFO (#0) myspan=1ms: message1
// message2
// v-- bold
// key2: value2
// key1: value1

@since3.5.0

pretty
)))

Output:

Terminal window
[11:37:14.265] INFO (#0) myspan=101ms: msg1
msg2
[ 'msg3', 'msg4' ]
key2: value2
key1: value1

The structuredLogger logger produces logs in a detailed object-based format. This format is helpful when you need more traceable logs, especially if other systems analyze them or store them for later review.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("msg1", "msg2", ["msg3", "msg4"]).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

@example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
// Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
({
key1: string
key1
: "value1",
key2: string
key2
: "value2" }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("myspan")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import Logger
Logger
.
const structured: Layer<never, never, never>

The structured logger provides detailed log outputs, structured in a way that retains comprehensive traceability of the events, suitable for deeper analysis and troubleshooting.

@example

import { Effect, Logger } from "effect"
const program = Effect.log("message1", "message2").pipe(
Effect.annotateLogs({ key1: "value1", key2: "value2" }),
Effect.withLogSpan("myspan")
)
// Effect.runFork(program.pipe(Effect.provide(Logger.structured)))
// {
// message: [ 'message1', 'message2' ],
// logLevel: 'INFO',
// timestamp: '2024-07-09T14:05:41.623Z',
// cause: undefined,
// annotations: { key2: 'value2', key1: 'value1' },
// spans: { myspan: 0 },
// fiberId: '#0'
// }

@since2.0.0

structured
)))

Output:

Terminal window
{
message: [ 'msg1', 'msg2', [ 'msg3', 'msg4' ] ],
logLevel: 'INFO',
timestamp: '2024-12-28T10:44:31.281Z',
cause: undefined,
annotations: { key2: 'value2', key1: 'value1' },
spans: { myspan: 102 },
fiberId: '#0'
}
FieldDescription
messageEither a single processed value or an array of processed values, depending on how many messages are logged.
logLevelA string that indicates the log level label (for example, “INFO” or “DEBUG”).
timestampAn ISO 8601 timestamp for when the log was generated (for example, “2024-01-01T00:00:00.000Z”).
causeA string that shows detailed error information, or undefined if no cause was provided.
annotationsAn object where each key is an annotation label and the corresponding value is parsed into a structured format (for instance, {"key": "value"}).
spansAn object mapping each span label to its duration in milliseconds, measured from its start time until the moment the logger was called (for example, {"myspan": 102}).
fiberIdThe identifier of the fiber that generated this log (for example, “#0”).

The jsonLogger logger produces logs in JSON format. This can be useful for tools or services that parse and store JSON logs. It calls JSON.stringify on the object created by the structuredLogger logger.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Logger
Logger
} from "effect"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

@example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
// Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("msg1", "msg2", ["msg3", "msg4"]).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>, bc: (_: Effect.Effect<...>) => Effect.Effect<...>, cd: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

@example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
// Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)

Adds custom annotations to log entries generated within an effect.

Details

This function allows you to enhance log messages by appending additional context in the form of key-value pairs. These annotations are included in every log message created during the execution of the effect, making the logs more informative and easier to trace.

The annotations can be specified as a single key-value pair or as a record of multiple key-value pairs. This is particularly useful for tracking operations, debugging, or associating specific metadata with logs for better observability.

The annotated key-value pairs will appear alongside the log message in the output.

@seeannotateLogsScoped to add log annotations with a limited scope.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.log("message1")
yield* Effect.log("message2")
}).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message=message1 taskId=1234
// timestamp=... level=INFO fiber=#0 message=message2 taskId=1234

@since2.0.0

annotateLogs
({
key1: string
key1
: "value1",
key2: string
key2
: "value2" }),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withLogSpan: (label: string) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Adds a log span to an effect for tracking and logging its execution duration.

Details

This function wraps an effect with a log span, providing performance monitoring and debugging capabilities. The log span tracks the duration of the wrapped effect and logs it with the specified label. This is particularly useful when analyzing time-sensitive operations or understanding the execution time of specific tasks in your application.

The logged output will include the label and the total time taken for the operation. The span information is included in the log metadata, making it easy to trace performance metrics in logs.

@example

import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.sleep("1 second")
yield* Effect.log("The job is finished!")
}).pipe(Effect.withLogSpan("myspan"))
// Effect.runFork(program)
// timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms

@since2.0.0

withLogSpan
("myspan")
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>

Runs an effect in the background, returning a fiber that can be observed or interrupted.

Unless you specifically need a Promise or synchronous operation, runFork is a good default choice.

Details

This function is the foundational way to execute an effect in the background. It creates a "fiber," a lightweight, cooperative thread of execution that can be observed (to access its result), interrupted, or joined. Fibers are useful for concurrent programming and allow effects to run independently of the main program flow.

Once the effect is running in a fiber, you can monitor its progress, cancel it if necessary, or retrieve its result when it completes. If the effect fails, the fiber will propagate the failure, which you can observe and handle.

When to Use

Use this function when you need to run an effect in the background, especially if the effect is long-running or performs periodic tasks. It's suitable for tasks that need to run independently but might still need observation or management, like logging, monitoring, or scheduled tasks.

This function is ideal if you don't need the result immediately or if the effect is part of a larger concurrent workflow.

@example

// Title: Running an Effect in the Background
import { Effect, Console, Schedule, Fiber } from "effect"
// ┌─── Effect<number, never, never>
// ▼
const program = Effect.repeat(
Console.log("running..."),
Schedule.spaced("200 millis")
)
// ┌─── RuntimeFiber<number, never>
// ▼
const fiber = Effect.runFork(program)
setTimeout(() => {
Effect.runFork(Fiber.interrupt(fiber))
}, 500)

@since2.0.0

runFork
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

@seeprovideService for providing a service to an effect.

@example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
// Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@since2.0.0

provide
(
import Logger
Logger
.
const json: Layer<never, never, never>

The json logger formats log entries as JSON objects, making them easy to integrate with logging systems that consume JSON data.

@example

import { Effect, Logger } from "effect"
const program = Effect.log("message1", "message2").pipe(
Effect.annotateLogs({ key1: "value1", key2: "value2" }),
Effect.withLogSpan("myspan")
)
// Effect.runFork(program.pipe(Effect.provide(Logger.json)))
// {"message":["message1","message2"],"logLevel":"INFO","timestamp":"...","annotations":{"key2":"value2","key1":"value1"},"spans":{"myspan":0},"fiberId":"#0"}

@since2.0.0

json
)))

Output:

Terminal window
{"message":["msg1","msg2",["msg3","msg4"]],"logLevel":"INFO","timestamp":"2024-12-28T10:44:31.281Z","annotations":{"key2":"value2","key1":"value1"},"spans":{"myspan":102},"fiberId":"#0"}

The Logger.zip function combines two loggers into a new logger. This new logger forwards log messages to both the original loggers.

Example (Combining Two Loggers)

import { Effect, Logger } from "effect"
// Define a custom logger that logs to the console
const logger = Logger.make(({ logLevel, message }) => {
globalThis.console.log(`[${logLevel.label}] ${message}`)
})
// Combine the default logger and the custom logger
//
// ┌─── Logger<unknown, [void, void]>
// ▼
const combined = Logger.zip(Logger.defaultLogger, logger)
const program = Effect.log("something")
Effect.runFork(
program.pipe(
// Replace the default logger with the combined logger
Effect.provide(Logger.replace(Logger.defaultLogger, combined))
)
)
/*
Output:
timestamp=2025-01-09T13:50:58.655Z level=INFO fiber=#0 message=something
[INFO] something
*/