Skip to content

Managing Layers

In the Managing Services page, you learned how to create effects which depend on some service to be provided in order to execute, as well as how to provide that service to an effect.

However, what if we have a service within our effect program that has dependencies on other services in order to be built? We want to avoid leaking these implementation details into the service interface.

To represent the “dependency graph” of our program and manage these dependencies more effectively, we can utilize a powerful abstraction called “Layer”.

Layers act as constructors for creating services, allowing us to manage dependencies during construction rather than at the service level. This approach helps to keep our service interfaces clean and focused.

Let’s review some key concepts before diving into the details:

ConceptDescription
serviceA reusable component providing specific functionality, used across different parts of an application.
tagA unique identifier representing a service, allowing Effect to locate and use it.
contextA collection storing services, functioning like a map with tags as keys and services as values.
layerAn abstraction for constructing services, managing dependencies during construction rather than at the service level.

Let’s imagine that we are building a web application. We could imagine that the dependency graph for an application where we need to manage configuration, logging, and database access might look something like this:

  • The Config service provides application configuration.
  • The Logger service depends on the Config service.
  • The Database service depends on both the Config and Logger services.

Our goal is to build the Database service along with its direct and indirect dependencies. This means we need to ensure that the Config service is available for both Logger and Database, and then provide these dependencies to the Database service.

When constructing the Database service, it’s important to avoid exposing the dependencies on Config and Logger within the Database interface.

You might be tempted to define the Database service as follows:

Example (Leaking Dependencies in the Service Interface)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
} from "effect"
// Declaring a tag for the Config service
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
, {}>() {}
// Declaring a tag for the Logger service
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
, {}>() {}
// Declaring a tag for the Database service
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{
// ❌ Avoid exposing Config and Logger as a requirement
readonly
query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
: (
sql: string
sql
: string
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<unknown, never,
class Config
Config
|
class Logger
Logger
>
}
>() {}

Here, the query function of the Database service requires both Config and Logger. This design leaks implementation details, making the Database service aware of its dependencies, which complicates testing and makes it difficult to mock.

To demonstrate the problem, let’s create a test instance of the Database service:

Example (Creating a Test Instance with Leaked Dependencies)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
} from "effect"
15 collapsed lines
// Declaring a tag for the Config service
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
, {}>() {}
// Declaring a tag for the Logger service
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
, {}>() {}
// Declaring a tag for the Database service
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{
readonly
query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
: (
sql: string
sql
: string
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<unknown, never,
class Config
Config
|
class Logger
Logger
>
}
>() {}
// Declaring a test instance of the Database service
const
const DatabaseTest: {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}
DatabaseTest
=
class Database
Database
.
Tag<Database, { readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>; }>.of(self: {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}): {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}
of
({
// Simulating a simple response
query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <never[]>(value: never[]) => Effect.Effect<never[], never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
([])
})
import * as
function assert(value: unknown, message?: string | Error): asserts value

An alias of

ok

.

@sincev0.5.9

@paramvalue The input that is checked for being truthy.

assert
from "node:assert"
// A test that uses the Database service
const
const test: Effect.Effect<void, never, Config | Logger | Database>
test
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Database, {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}>> | YieldWrap<...>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 database: {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}
database
= yield*
class Database
Database
const
const result: unknown
result
= yield*
const database: {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}
database
.
query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
("SELECT * FROM users")
function assert(value: unknown, message?: string | Error): asserts value

An alias of

ok

.

@sincev0.5.9

@paramvalue The input that is checked for being truthy.

assert
.
function assert.deepStrictEqual<never[]>(actual: unknown, expected: never[], message?: string | Error): asserts actual is never[]

Tests for deep equality between the actual and expected parameters. "Deep" equality means that the enumerable "own" properties of child objects are recursively evaluated also by the following rules.

@sincev1.2.0

deepStrictEqual
(
const result: unknown
result
, [])
})
// ┌─── Effect<unknown, never, Config | Logger>
// ▼
const
const incompleteTestSetup: Effect.Effect<void, never, Config | Logger>
incompleteTestSetup
=
const test: Effect.Effect<void, never, Config | Logger | Database>
test
.
Pipeable.pipe<Effect.Effect<void, never, Config | Logger | Database>, Effect.Effect<void, never, Config | Logger>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<...>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe
(
// Attempt to provide only the Database service without Config and Logger
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provideService: <typeof Database>(tag: typeof Database, service: {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}) => <A, E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+1 overload)

The provideService function is used to provide an actual implementation for a service in the context of an effect.

This function allows you to associate a service with its implementation so that it can be used in your program. You define the service (e.g., a random number generator), and then you use provideService to link that service to its implementation. Once the implementation is provided, the effect can be run successfully without further requirements.

@seeprovide for providing multiple layers to an effect.

@example

import { Effect, Context } from "effect"
// Declaring a tag for a service that generates random numbers
class Random extends Context.Tag("MyRandomService")<
Random,
{ readonly next: Effect.Effect<number> }
>() {}
// Using the service
const program = Effect.gen(function* () {
const random = yield* Random
const randomNumber = yield* random.next
console.log(`random number: ${randomNumber}`)
})
// Providing the implementation
//
// ┌─── Effect<void, never, never>
// ▼
const runnable = Effect.provideService(program, Random, {
next: Effect.sync(() => Math.random())
})
// Run successfully
Effect.runPromise(runnable)
// Example Output:
// random number: 0.8241872233134417

@since2.0.0

provideService
(
class Database
Database
,
const DatabaseTest: {
readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>;
}
DatabaseTest
)
)

Because the Database service interface directly includes dependencies on Config and Logger, it forces any test setup to include these services, even if they’re irrelevant to the test. This adds unnecessary complexity and makes it difficult to write simple, isolated unit tests.

Instead of directly tying dependencies to the Database service interface, dependencies should be managed at the construction phase.

We can use layers to properly construct the Database service and manage its dependencies without leaking details into the interface.

The Layer type is structured as follows:

┌─── The service to be created
│ ┌─── The possible error
│ │ ┌─── The required dependencies
▼ ▼ ▼
Layer<RequirementsOut, Error, RequirementsIn>

A Layer represents a blueprint for constructing a RequirementsOut (the service). It requires a RequirementsIn (dependencies) as input and may result in an error of type Error during the construction process.

ParameterDescription
RequirementsOutThe service or resource to be created.
ErrorThe type of error that might occur during the construction of the service.
RequirementsInThe dependencies required to construct the service.

By using layers, you can better organize your services, ensuring that their dependencies are clearly defined and separated from their implementation details.

For simplicity, let’s assume that we won’t encounter any errors during the value construction (meaning Error = never).

Now, let’s determine how many layers we need to implement our dependency graph:

LayerDependenciesType
ConfigLiveThe Config service does not depend on any other servicesLayer<Config>
LoggerLiveThe Logger service depends on the Config serviceLayer<Logger, never, Config>
DatabaseLiveThe Database service depends on Config and LoggerLayer<Database, never, Config | Logger>

When a service has multiple dependencies, they are represented as a union type. In our case, the Database service depends on both the Config and Logger services. Therefore, the type for the DatabaseLive layer will be:

Layer<Database, never, Config | Logger>

The Config service does not depend on any other services, so ConfigLive will be the simplest layer to implement. Just like in the Managing Services page, we must create a tag for the service. And because the service has no dependencies, we can create the layer directly using the Layer.succeed constructor:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
// Layer<Config, never, never>
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
,
class Config
Config
.
Tag<Config, { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }>.of(self: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}): {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
of
({
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
)

Looking at the type of ConfigLive we can observe:

  • RequirementsOut is Config, indicating that constructing the layer will produce a Config service
  • Error is never, indicating that layer construction cannot fail
  • RequirementsIn is never, indicating that the layer has no dependencies

Note that, to construct ConfigLive, we used the Config.of constructor. However, this is merely a helper to ensure correct type inference for the implementation. It’s possible to skip this helper and construct the implementation directly as a simple object:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
9 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
// Layer<Config, never, never>
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})

Now we can move on to the implementation of the Logger service, which depends on the Config service to retrieve some configuration.

Just like we did in the Managing Services page, we can yield the Config tag to “extract” the service from the context.

Given that using the Config tag is an effectful operation, we use Layer.effect to create a layer from the resulting effect.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
17 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
// Layer<Config, never, never>
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
// Declaring a tag for the Logger service
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
,
{ readonly
log: (message: string) => Effect.Effect<void>
log
: (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<void> }
>() {}
// Layer<Logger, never, Config>
const
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
=
import Layer
Layer
.
const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Logger
Logger
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
return {
log: (message: string) => Effect.Effect<void, never, never>
log
: (
message: string
message
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 logLevel: string
logLevel
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
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
(`[${
const logLevel: string
logLevel
}] ${
message: string
message
}`)
})
}
})
)

Looking at the type of LoggerLive:

Layer<Logger, never, Config>

we can observe that:

  • RequirementsOut is Logger
  • Error is never, indicating that layer construction cannot fail
  • RequirementsIn is Config, indicating that the layer has a requirement

Finally, we can use our Config and Logger services to implement the Database service.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
17 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
// Layer<Config, never, never>
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
// Declaring a tag for the Logger service
19 collapsed lines
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
,
{ readonly
log: (message: string) => Effect.Effect<void>
log
: (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<void> }
>() {}
// Layer<Logger, never, Config>
const
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
=
import Layer
Layer
.
const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Logger
Logger
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
return {
log: (message: string) => Effect.Effect<void, never, never>
log
: (
message: string
message
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 logLevel: string
logLevel
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
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
(`[${
const logLevel: string
logLevel
}] ${
message: string
message
}`)
})
}
})
)
// Declaring a tag for the Database service
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{ readonly
query: (sql: string) => Effect.Effect<unknown>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<unknown> }
>() {}
// Layer<Database, never, Config | Logger>
const
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
=
import Layer
Layer
.
const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Database
Database
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
const
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
= yield*
class Logger
Logger
return {
query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

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*
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
.
log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
sql: string
sql
}`)
const {
const connection: string
connection
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
return {
result: string
result
: `Results from ${
const connection: string
connection
}` }
})
}
})
)

Looking at the type of DatabaseLive:

Layer<Database, never, Config | Logger>

we can observe that the RequirementsIn type is Config | Logger, i.e., the Database service requires both Config and Logger services.

Layers can be combined in two primary ways: merging and composing.

Layers can be combined through merging using the Layer.merge function:

import {
import Layer
Layer
} from "effect"
declare const
const layer1: Layer.Layer<"Out1", never, "In1">
layer1
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never>

@since2.0.0

@since2.0.0

Layer
<"Out1", never, "In1">
declare const
const layer2: Layer.Layer<"Out2", never, "In2">
layer2
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never>

@since2.0.0

@since2.0.0

Layer
<"Out2", never, "In2">
// Layer<"Out1" | "Out2", never, "In1" | "In2">
const
const merging: Layer.Layer<"Out1" | "Out2", never, "In1" | "In2">
merging
=
import Layer
Layer
.
const merge: <"In1", never, "Out1", "In2", never, "Out2">(self: Layer.Layer<"Out1", never, "In1">, that: Layer.Layer<"Out2", never, "In2">) => Layer.Layer<"Out1" | "Out2", never, "In1" | "In2"> (+1 overload)

Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.

@since2.0.0

merge
(
const layer1: Layer.Layer<"Out1", never, "In1">
layer1
,
const layer2: Layer.Layer<"Out2", never, "In2">
layer2
)

When we merge two layers, the resulting layer:

  • requires all the services that both of them require ("In1" | "In2").
  • produces all services that both of them produce ("Out1" | "Out2").

For example, in our web application above, we can merge our ConfigLive and LoggerLive layers into a single AppConfigLive layer, which retains the requirements of both layers (never | Config = Config) and the outputs of both layers (Config | Logger):

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
17 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
// Layer<Config, never, never>
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
// Declaring a tag for the Logger service
19 collapsed lines
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
,
{ readonly
log: (message: string) => Effect.Effect<void>
log
: (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<void> }
>() {}
// Layer<Logger, never, Config>
const
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
=
import Layer
Layer
.
const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Logger
Logger
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
return {
log: (message: string) => Effect.Effect<void, never, never>
log
: (
message: string
message
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 logLevel: string
logLevel
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
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
(`[${
const logLevel: string
logLevel
}] ${
message: string
message
}`)
})
}
})
)
// Layer<Config | Logger, never, Config>
const
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
=
import Layer
Layer
.
const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)

Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.

@since2.0.0

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)

Layers can be composed using the Layer.provide function:

import {
import Layer
Layer
} from "effect"
declare const
const inner: Layer.Layer<"OutInner", never, "InInner">
inner
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never>

@since2.0.0

@since2.0.0

Layer
<"OutInner", never, "InInner">
declare const
const outer: Layer.Layer<"InInner", never, "InOuter">
outer
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never>

@since2.0.0

@since2.0.0

Layer
<"InInner", never, "InOuter">
// Layer<"OutInner", never, "InOuter">
const
const composition: Layer.Layer<"OutInner", never, "InOuter">
composition
=
import Layer
Layer
.
const provide: <"InInner", never, "OutInner", "InOuter", never, "InInner">(self: Layer.Layer<"OutInner", never, "InInner">, that: Layer.Layer<"InInner", never, "InOuter">) => Layer.Layer<"OutInner", never, "InOuter"> (+3 overloads)

Feeds the output services of this builder into the input of the specified builder, resulting in a new builder with the inputs of this builder as well as any leftover inputs, and the outputs of the specified builder.

@since2.0.0

provide
(
const inner: Layer.Layer<"OutInner", never, "InInner">
inner
,
const outer: Layer.Layer<"InInner", never, "InOuter">
outer
)

Sequential composition of layers implies that the output of one layer is supplied as the input for the inner layer, resulting in a single layer with the requirements of the outer layer and the output of the inner.

Now we can compose the AppConfigLive layer with the DatabaseLive layer:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
17 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
// Layer<Config, never, never>
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
// Declaring a tag for the Logger service
19 collapsed lines
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
,
{ readonly
log: (message: string) => Effect.Effect<void>
log
: (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<void> }
>() {}
// Layer<Logger, never, Config>
const
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
=
import Layer
Layer
.
const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Logger
Logger
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
return {
log: (message: string) => Effect.Effect<void, never, never>
log
: (
message: string
message
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 logLevel: string
logLevel
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
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
(`[${
const logLevel: string
logLevel
}] ${
message: string
message
}`)
})
}
})
)
// Declaring a tag for the Database service
21 collapsed lines
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{ readonly
query: (sql: string) => Effect.Effect<unknown>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<unknown> }
>() {}
// Layer<Database, never, Config | Logger>
const
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
=
import Layer
Layer
.
const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Database
Database
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
const
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
= yield*
class Logger
Logger
return {
query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

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*
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
.
log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
sql: string
sql
}`)
const {
const connection: string
connection
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
return {
result: string
result
: `Results from ${
const connection: string
connection
}` }
})
}
})
)
// Layer<Config | Logger, never, Config>
const
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
=
import Layer
Layer
.
const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)

Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.

@since2.0.0

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)
// Layer<Database, never, never>
const
const MainLive: Layer.Layer<Database, never, never>
MainLive
=
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
.
Pipeable.pipe<Layer.Layer<Database, never, Config | Logger>, Layer.Layer<Database, never, Config>, Layer.Layer<Database, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe
(
// provides the config and logger to the database
import Layer
Layer
.
const provide: <Config, never, Config | Logger>(that: Layer.Layer<Config | Logger, never, Config>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)

Feeds the output services of this builder into the input of the specified builder, resulting in a new builder with the inputs of this builder as well as any leftover inputs, and the outputs of the specified builder.

@since2.0.0

provide
(
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
),
// provides the config to AppConfigLive
import Layer
Layer
.
const provide: <never, never, Config>(that: Layer.Layer<Config, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<...> (+3 overloads)

Feeds the output services of this builder into the input of the specified builder, resulting in a new builder with the inputs of this builder as well as any leftover inputs, and the outputs of the specified builder.

@since2.0.0

provide
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
)
)

We obtained a MainLive layer that produces the Database service:

Layer<Database, never, never>

This layer is the fully resolved layer for our application.

Let’s say we want our MainLive layer to return both the Config and Database services. We can achieve this with Layer.provideMerge:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
// Declaring a tag for the Config service
16 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
// Declaring a tag for the Logger service
18 collapsed lines
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
,
{ readonly
log: (message: string) => Effect.Effect<void>
log
: (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<void> }
>() {}
const
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
=
import Layer
Layer
.
const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Logger
Logger
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
return {
log: (message: string) => Effect.Effect<void, never, never>
log
: (
message: string
message
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 logLevel: string
logLevel
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
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
(`[${
const logLevel: string
logLevel
}] ${
message: string
message
}`)
})
}
})
)
// Declaring a tag for the Database service
20 collapsed lines
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{ readonly
query: (sql: string) => Effect.Effect<unknown>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<unknown> }
>() {}
const
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
=
import Layer
Layer
.
const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Database
Database
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
const
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
= yield*
class Logger
Logger
return {
query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

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*
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
.
log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
sql: string
sql
}`)
const {
const connection: string
connection
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
return {
result: string
result
: `Results from ${
const connection: string
connection
}` }
})
}
})
)
// Layer<Config | Logger, never, Config>
const
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
=
import Layer
Layer
.
const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)

Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.

@since2.0.0

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)
// Layer<Config | Database, never, never>
const
const MainLive: Layer.Layer<Config | Database, never, never>
MainLive
=
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
.
Pipeable.pipe<Layer.Layer<Database, never, Config | Logger>, Layer.Layer<Database, never, Config>, Layer.Layer<Config | Database, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe
(
import Layer
Layer
.
const provide: <Config, never, Config | Logger>(that: Layer.Layer<Config | Logger, never, Config>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)

Feeds the output services of this builder into the input of the specified builder, resulting in a new builder with the inputs of this builder as well as any leftover inputs, and the outputs of the specified builder.

@since2.0.0

provide
(
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
),
import Layer
Layer
.
const provideMerge: <never, never, Config>(self: Layer.Layer<Config, never, never>) => <RIn2, E2, ROut2>(that: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<...> (+1 overload)

Feeds the output services of this layer into the input of the specified layer, resulting in a new layer with the inputs of this layer, and the outputs of both layers.

@since2.0.0

provideMerge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
)
)

Now that we have assembled the fully resolved MainLive for our application, we can provide it to our program to satisfy the program’s requirements using Effect.provide:

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Context

@since2.0.0

@since2.0.0

Context
,
import Layer
Layer
} from "effect"
63 collapsed lines
class
class Config
Config
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Config")<
class Config
Config
,
{
readonly
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<{
readonly
logLevel: string
logLevel
: string
readonly
connection: string
connection
: string
}>
}
>() {}
const
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
=
import Layer
Layer
.
const succeed: <typeof Config>(tag: typeof Config, resource: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}) => Layer.Layer<Config, never, never> (+1 overload)

Constructs a layer from the specified value.

@since2.0.0

succeed
(
class Config
Config
, {
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const succeed: <{
logLevel: string;
connection: string;
}>(value: {
logLevel: string;
connection: string;
}) => Effect.Effect<{
logLevel: string;
connection: string;
}, never, never>

Creates an Effect that always succeeds with a given value.

When to Use

Use this function when you need an effect that completes successfully with a specific value without any errors or external dependencies.

@seefail to create an effect that represents a failure.

@example

// Title: Creating a Successful Effect
import { Effect } from "effect"
// Creating an effect that represents a successful scenario
//
// ┌─── Effect<number, never, never>
// ▼
const success = Effect.succeed(42)

@since2.0.0

succeed
({
logLevel: string
logLevel
: "INFO",
connection: string
connection
: "mysql://username:password@hostname:port/database_name"
})
})
class
class Logger
Logger
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Logger")<
class Logger
Logger
,
{ readonly
log: (message: string) => Effect.Effect<void>
log
: (
message: string
message
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<void> }
>() {}
const
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
=
import Layer
Layer
.
const effect: <typeof Logger, never, Config>(tag: typeof Logger, effect: Effect.Effect<{
readonly log: (message: string) => Effect.Effect<void>;
}, never, Config>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Logger
Logger
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
return {
log: (message: string) => Effect.Effect<void, never, never>
log
: (
message: string
message
) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 logLevel: string
logLevel
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
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
(`[${
const logLevel: string
logLevel
}] ${
message: string
message
}`)
})
}
})
)
class
class Database
Database
extends
import Context

@since2.0.0

@since2.0.0

Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape>

@example

import { Context, Layer } from "effect"
class MyTag extends Context.Tag("MyTag")<
MyTag,
{ readonly myNum: number }
>() {
static Live = Layer.succeed(this, { myNum: 108 })
}

@since2.0.0

Tag
("Database")<
class Database
Database
,
{ readonly
query: (sql: string) => Effect.Effect<unknown>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that lazily describes a workflow or job. The workflow requires some context R, and may fail with an error of type E, or succeed with a value of type A.

Effect values model resourceful interaction with the outside world, including synchronous, asynchronous, concurrent, and parallel interaction. They use a fiber-based concurrency model, with built-in support for scheduling, fine-grained interruption, structured concurrency, and high scalability.

To run an Effect value, you need a Runtime, which is a type that is capable of executing Effect values.

@since2.0.0

@since2.0.0

Effect
<unknown> }
>() {}
const
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
=
import Layer
Layer
.
const effect: <typeof Database, never, Config | Logger>(tag: typeof Database, effect: Effect.Effect<{
readonly query: (sql: string) => Effect.Effect<unknown>;
}, never, Config | Logger>) => Layer.Layer<...> (+1 overload)

Constructs a layer from the specified effect.

@since2.0.0

effect
(
class Database
Database
,
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Config, {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}>> | YieldWrap<...>, {
...;
}>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
= yield*
class Config
Config
const
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
= yield*
class Logger
Logger
return {
query: (sql: string) => Effect.Effect<{
result: string;
}, never, never>
query
: (
sql: string
sql
: string) =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

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

When to Use

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*
const logger: {
readonly log: (message: string) => Effect.Effect<void>;
}
logger
.
log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
sql: string
sql
}`)
const {
const connection: string
connection
} = yield*
const config: {
readonly getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}>;
}
config
.
getConfig: Effect.Effect<{
readonly logLevel: string;
readonly connection: string;
}, never, never>
getConfig
return {
result: string
result
: `Results from ${
const connection: string
connection
}` }
})
}
})
)
const
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
=
import Layer
Layer
.
const merge: <never, never, Config, Config, never, Logger>(self: Layer.Layer<Config, never, never>, that: Layer.Layer<Logger, never, Config>) => Layer.Layer<...> (+1 overload)

Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.

@since2.0.0

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)
const
const MainLive: Layer.Layer<Database, never, never>
MainLive
=
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
.
Pipeable.pipe<Layer.Layer<Database, never, Config | Logger>, Layer.Layer<Database, never, Config>, Layer.Layer<Database, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<...>) => Layer.Layer<...>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)
pipe
(
import Layer
Layer
.
const provide: <Config, never, Config | Logger>(that: Layer.Layer<Config | Logger, never, Config>) => <RIn2, E2, ROut2>(self: Layer.Layer<...>) => Layer.Layer<...> (+3 overloads)

Feeds the output services of this builder into the input of the specified builder, resulting in a new builder with the inputs of this builder as well as any leftover inputs, and the outputs of the specified builder.

@since2.0.0

provide
(
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
),
import Layer
Layer
.
const provide: <never, never, Config>(that: Layer.Layer<Config, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<...> (+3 overloads)

Feeds the output services of this builder into the input of the specified builder, resulting in a new builder with the inputs of this builder as well as any leftover inputs, and the outputs of the specified builder.

@since2.0.0

provide
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
)
)
// ┌─── Effect<unknown, never, Database>
// ▼
const
const program: Effect.Effect<unknown, never, Database>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Context.Tag<Database, {
readonly query: (sql: string) => Effect.Effect<unknown>;
}>> | YieldWrap<Effect.Effect<unknown, never, never>>, unknown>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)

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

When to Use

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 database: {
readonly query: (sql: string) => Effect.Effect<unknown>;
}
database
= yield*
class Database
Database
const
const result: unknown
result
= yield*
const database: {
readonly query: (sql: string) => Effect.Effect<unknown>;
}
database
.
query: (sql: string) => Effect.Effect<unknown>
query
("SELECT * FROM users")
return
const result: unknown
result
})
// ┌─── Effect<unknown, never, never>
// ▼
const
const runnable: Effect.Effect<unknown, never, never>
runnable
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

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

Provides the necessary Layers to an effect, removing its dependency on the environment.

You can pass multiple layers, a Context, Runtime, or ManagedRuntime to the effect.

@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<unknown, never, Database>
program
,
const MainLive: Layer.Layer<Database, never, never>
MainLive
)
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<unknown>

Executes an effect and returns the result as a Promise.

When to Use

Use runPromise when you need to execute an effect and work with the result using Promise syntax, typically for compatibility with other promise-based code.

If the effect succeeds, the promise will resolve with the result. If the effect fails, the promise will reject with an error.

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@example

// Title: Running a Successful Effect as a Promise
import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

@example

//Example: Handling a Failing Effect as a Rejected Promise import { Effect } from "effect"

Effect.runPromise(Effect.fail("my error")).catch(console.error) // Output: // (FiberFailure) Error: my error

@since2.0.0

runPromise
(
const runnable: Effect.Effect<unknown, never, never>
runnable
).
Promise<unknown>.then<void, never>(onfulfilled?: ((value: unknown) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
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
)
/*
Output:
[INFO] Executing query: SELECT * FROM users
{
result: 'Results from mysql://username:password@hostname:port/database_name'
}
*/

Note that the runnable requirements type is never, indicating that the program does not require any additional services to run.