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)

1
import {
import Effect
Effect
,
import Context
Context
} from "effect"
2
3
// Declaring a tag for the Config service
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
class Config
Config
, {}>() {}
5
6
// Declaring a tag for the Logger service
7
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
class Logger
Logger
, {}>() {}
8
9
// Declaring a tag for the Database service
10
class
class Database
Database
extends
import Context
Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape> namespace Tag
Tag
("Database")<
11
class Database
Database
,
12
{
13
// ❌ Avoid exposing Config and Logger as a requirement
14
readonly
(property) query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
: (
15
(parameter) sql: string
sql
: string
16
) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

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

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)

1
import {
import Effect
Effect
,
import Context
Context
} from "effect"
2
15 collapsed lines
3
// Declaring a tag for the Config service
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
class Config
Config
, {}>() {}
5
6
// Declaring a tag for the Logger service
7
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
class Logger
Logger
, {}>() {}
8
9
// Declaring a tag for the Database service
10
class
class Database
Database
extends
import Context
Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape> namespace Tag
Tag
("Database")<
11
class Database
Database
,
12
{
13
readonly
(property) query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
: (
14
(parameter) sql: string
sql
: string
15
) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<unknown, never,
class Config
Config
|
class Logger
Logger
>
16
}
17
>() {}
18
19
// Declaring a test instance of the Database service
20
const
const DatabaseTest: { readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>; }
DatabaseTest
=
class Database
Database
.
(method) 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
({
21
// Simulating a simple response
22
(property) query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
: (
(parameter) sql: string
sql
: string) =>
import Effect
Effect
.
const succeed: <never[]>(value: never[]) => Effect.Effect<never[], never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

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

An alias of {@link ok } .

assert
from "node:assert"
26
27
// A test that uses the Database service
28
const
const test: Effect.Effect<void, never, Config | Logger | Database>
test
=
import Effect
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)
gen
(function* () {
29
const
const database: { readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>; }
database
= yield*
class Database
Database
30
const
const result: unknown
result
= yield*
const database: { readonly query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>; }
database
.
(property) query: (sql: string) => Effect.Effect<unknown, never, Config | Logger>
query
("SELECT * FROM users")
31
(alias) function assert(value: unknown, message?: string | Error): asserts value (alias) namespace assert import assert

An alias of {@link ok } .

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.

deepStrictEqual
(
const result: unknown
result
, [])
32
})
33
34
// ┌─── Effect<unknown, never, Config | Logger>
35
// ▼
36
const
const incompleteTestSetup: Effect.Effect<void, never, Config | Logger>
incompleteTestSetup
=
const test: Effect.Effect<void, never, Config | Logger | Database>
test
.
(method) 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
(
37
// Attempt to provide only the Database service without Config and Logger
38
import Effect
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)

Provides the effect with the single service it requires. If the effect requires more than one service use `provide` instead.

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

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:

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
// Layer<Config, never, never>
15
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.

succeed
(
16
class Config
Config
,
17
class Config
Config
.
(method) 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
({
18
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
19
(property) logLevel: string
logLevel
: "INFO",
20
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
21
})
22
})
23
)

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:

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
9 collapsed lines
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
// Layer<Config, never, never>
15
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.

succeed
(
class Config
Config
, {
16
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

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

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.

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
17 collapsed lines
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
// Layer<Config, never, never>
15
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.

succeed
(
class Config
Config
, {
16
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
17
(property) logLevel: string
logLevel
: "INFO",
18
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
19
})
20
})
21
22
// Declaring a tag for the Logger service
23
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
24
class Logger
Logger
,
25
{ readonly
(property) log: (message: string) => Effect.Effect<void>
log
: (
(parameter) message: string
message
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<void> }
26
>() {}
27
28
// Layer<Logger, never, Config>
29
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.

effect
(
30
class Logger
Logger
,
31
import Effect
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)
gen
(function* () {
32
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
33
return {
34
(property) log: (message: string) => Effect.Effect<void, never, never>
log
: (
(parameter) message: string
message
) =>
35
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
36
const {
const logLevel: string
logLevel
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
37
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`[${
const logLevel: string
logLevel
}] ${
(parameter) message: string
message
}`)
38
})
39
}
40
})
41
)

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.

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
17 collapsed lines
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
// Layer<Config, never, never>
15
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.

succeed
(
class Config
Config
, {
16
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
17
(property) logLevel: string
logLevel
: "INFO",
18
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
19
})
20
})
21
22
// Declaring a tag for the Logger service
19 collapsed lines
23
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
24
class Logger
Logger
,
25
{ readonly
(property) log: (message: string) => Effect.Effect<void>
log
: (
(parameter) message: string
message
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<void> }
26
>() {}
27
28
// Layer<Logger, never, Config>
29
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.

effect
(
30
class Logger
Logger
,
31
import Effect
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)
gen
(function* () {
32
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
33
return {
34
(property) log: (message: string) => Effect.Effect<void, never, never>
log
: (
(parameter) message: string
message
) =>
35
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
36
const {
const logLevel: string
logLevel
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
37
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`[${
const logLevel: string
logLevel
}] ${
(parameter) message: string
message
}`)
38
})
39
}
40
})
41
)
42
43
// Declaring a tag for the Database service
44
class
class Database
Database
extends
import Context
Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape> namespace Tag
Tag
("Database")<
45
class Database
Database
,
46
{ readonly
(property) query: (sql: string) => Effect.Effect<unknown>
query
: (
(parameter) sql: string
sql
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<unknown> }
47
>() {}
48
49
// Layer<Database, never, Config | Logger>
50
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.

effect
(
51
class Database
Database
,
52
import Effect
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)
gen
(function* () {
53
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
54
const
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
= yield*
class Logger
Logger
55
return {
56
(property) query: (sql: string) => Effect.Effect<{ result: string; }, never, never>
query
: (
(parameter) sql: string
sql
: string) =>
57
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, { result: string; }>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, { ...; }, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
58
yield*
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
.
(property) log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
(parameter) sql: string
sql
}`)
59
const {
const connection: string
connection
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
60
return {
(property) result: string
result
: `Results from ${
const connection: string
connection
}` }
61
})
62
}
63
})
64
)

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:

1
import {
import Layer
Layer
} from "effect"
2
3
declare const
const layer1: Layer.Layer<"Out1", never, "In1">
layer1
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never> namespace Layer
Layer
<"Out1", never, "In1">
4
declare const
const layer2: Layer.Layer<"Out2", never, "In2">
layer2
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never> namespace Layer
Layer
<"Out2", never, "In2">
5
6
// Layer<"Out1" | "Out2", never, "In1" | "In2">
7
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.

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):

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
17 collapsed lines
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
// Layer<Config, never, never>
15
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.

succeed
(
class Config
Config
, {
16
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
17
(property) logLevel: string
logLevel
: "INFO",
18
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
19
})
20
})
21
22
// Declaring a tag for the Logger service
19 collapsed lines
23
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
24
class Logger
Logger
,
25
{ readonly
(property) log: (message: string) => Effect.Effect<void>
log
: (
(parameter) message: string
message
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<void> }
26
>() {}
27
28
// Layer<Logger, never, Config>
29
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.

effect
(
30
class Logger
Logger
,
31
import Effect
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)
gen
(function* () {
32
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
33
return {
34
(property) log: (message: string) => Effect.Effect<void, never, never>
log
: (
(parameter) message: string
message
) =>
35
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
36
const {
const logLevel: string
logLevel
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
37
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`[${
const logLevel: string
logLevel
}] ${
(parameter) message: string
message
}`)
38
})
39
}
40
})
41
)
42
43
// Layer<Config | Logger, never, Config>
44
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.

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:

1
import {
import Layer
Layer
} from "effect"
2
3
declare const
const inner: Layer.Layer<"OutInner", never, "InInner">
inner
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never> namespace Layer
Layer
<"OutInner", never, "InInner">
4
declare const
const outer: Layer.Layer<"InInner", never, "InOuter">
outer
:
import Layer
Layer
.
interface Layer<in ROut, out E = never, out RIn = never> namespace Layer
Layer
<"InInner", never, "InOuter">
5
6
// Layer<"OutInner", never, "InOuter">
7
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.

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:

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
17 collapsed lines
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
// Layer<Config, never, never>
15
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.

succeed
(
class Config
Config
, {
16
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
17
(property) logLevel: string
logLevel
: "INFO",
18
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
19
})
20
})
21
22
// Declaring a tag for the Logger service
19 collapsed lines
23
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
24
class Logger
Logger
,
25
{ readonly
(property) log: (message: string) => Effect.Effect<void>
log
: (
(parameter) message: string
message
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<void> }
26
>() {}
27
28
// Layer<Logger, never, Config>
29
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.

effect
(
30
class Logger
Logger
,
31
import Effect
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)
gen
(function* () {
32
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
33
return {
34
(property) log: (message: string) => Effect.Effect<void, never, never>
log
: (
(parameter) message: string
message
) =>
35
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
36
const {
const logLevel: string
logLevel
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
37
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`[${
const logLevel: string
logLevel
}] ${
(parameter) message: string
message
}`)
38
})
39
}
40
})
41
)
42
43
// Declaring a tag for the Database service
21 collapsed lines
44
class
class Database
Database
extends
import Context
Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape> namespace Tag
Tag
("Database")<
45
class Database
Database
,
46
{ readonly
(property) query: (sql: string) => Effect.Effect<unknown>
query
: (
(parameter) sql: string
sql
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<unknown> }
47
>() {}
48
49
// Layer<Database, never, Config | Logger>
50
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.

effect
(
51
class Database
Database
,
52
import Effect
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)
gen
(function* () {
53
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
54
const
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
= yield*
class Logger
Logger
55
return {
56
(property) query: (sql: string) => Effect.Effect<{ result: string; }, never, never>
query
: (
(parameter) sql: string
sql
: string) =>
57
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, { result: string; }>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, { ...; }, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
58
yield*
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
.
(property) log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
(parameter) sql: string
sql
}`)
59
const {
const connection: string
connection
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
60
return {
(property) result: string
result
: `Results from ${
const connection: string
connection
}` }
61
})
62
}
63
})
64
)
65
66
// Layer<Config | Logger, never, Config>
67
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.

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)
68
69
// Layer<Database, never, never>
70
const
const MainLive: Layer.Layer<Database, never, never>
MainLive
=
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
.
(method) 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
(
71
// provides the config and logger to the database
72
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.

provide
(
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
),
73
// provides the config to AppConfigLive
74
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.

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

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:

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
3
// Declaring a tag for the Config service
16 collapsed lines
4
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
5
class Config
Config
,
6
{
7
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
8
readonly
(property) logLevel: string
logLevel
: string
9
readonly
(property) connection: string
connection
: string
10
}>
11
}
12
>() {}
13
14
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.

succeed
(
class Config
Config
, {
15
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
16
(property) logLevel: string
logLevel
: "INFO",
17
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
18
})
19
})
20
21
// Declaring a tag for the Logger service
18 collapsed lines
22
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
23
class Logger
Logger
,
24
{ readonly
(property) log: (message: string) => Effect.Effect<void>
log
: (
(parameter) message: string
message
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<void> }
25
>() {}
26
27
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.

effect
(
28
class Logger
Logger
,
29
import Effect
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)
gen
(function* () {
30
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
31
return {
32
(property) log: (message: string) => Effect.Effect<void, never, never>
log
: (
(parameter) message: string
message
) =>
33
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
34
const {
const logLevel: string
logLevel
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
35
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`[${
const logLevel: string
logLevel
}] ${
(parameter) message: string
message
}`)
36
})
37
}
38
})
39
)
40
41
// Declaring a tag for the Database service
20 collapsed lines
42
class
class Database
Database
extends
import Context
Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape> namespace Tag
Tag
("Database")<
43
class Database
Database
,
44
{ readonly
(property) query: (sql: string) => Effect.Effect<unknown>
query
: (
(parameter) sql: string
sql
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<unknown> }
45
>() {}
46
47
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.

effect
(
48
class Database
Database
,
49
import Effect
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)
gen
(function* () {
50
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
51
const
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
= yield*
class Logger
Logger
52
return {
53
(property) query: (sql: string) => Effect.Effect<{ result: string; }, never, never>
query
: (
(parameter) sql: string
sql
: string) =>
54
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, { result: string; }>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, { ...; }, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
55
yield*
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
.
(property) log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
(parameter) sql: string
sql
}`)
56
const {
const connection: string
connection
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
57
return {
(property) result: string
result
: `Results from ${
const connection: string
connection
}` }
58
})
59
}
60
})
61
)
62
63
// Layer<Config | Logger, never, Config>
64
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.

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)
65
66
// Layer<Config | Database, never, never>
67
const
const MainLive: Layer.Layer<Config | Database, never, never>
MainLive
=
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
.
(method) 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
(
68
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.

provide
(
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
),
69
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.

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

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:

1
import {
import Effect
Effect
,
import Context
Context
,
import Layer
Layer
} from "effect"
2
63 collapsed lines
3
class
class Config
Config
extends
import Context
Context
.
const Tag: <"Config">(id: "Config") => <Self, Shape>() => Context.TagClass<Self, "Config", Shape> namespace Tag
Tag
("Config")<
4
class Config
Config
,
5
{
6
readonly
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<{
7
readonly
(property) logLevel: string
logLevel
: string
8
readonly
(property) connection: string
connection
: string
9
}>
10
}
11
>() {}
12
13
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.

succeed
(
class Config
Config
, {
14
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
:
import Effect
Effect
.
const succeed: <{ logLevel: string; connection: string; }>(value: { logLevel: string; connection: string; }) => Effect.Effect<{ logLevel: string; connection: string; }, never, never>

Creates an `Effect` that succeeds with the provided value. Use this function to represent a successful computation that yields a value of type `A`. The effect does not fail and does not require any environmental context.

succeed
({
15
(property) logLevel: string
logLevel
: "INFO",
16
(property) connection: string
connection
: "mysql://username:password@hostname:port/database_name"
17
})
18
})
19
20
class
class Logger
Logger
extends
import Context
Context
.
const Tag: <"Logger">(id: "Logger") => <Self, Shape>() => Context.TagClass<Self, "Logger", Shape> namespace Tag
Tag
("Logger")<
21
class Logger
Logger
,
22
{ readonly
(property) log: (message: string) => Effect.Effect<void>
log
: (
(parameter) message: string
message
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<void> }
23
>() {}
24
25
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.

effect
(
26
class Logger
Logger
,
27
import Effect
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)
gen
(function* () {
28
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
29
return {
30
(property) log: (message: string) => Effect.Effect<void, never, never>
log
: (
(parameter) message: string
message
) =>
31
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
32
const {
const logLevel: string
logLevel
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
33
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
(`[${
const logLevel: string
logLevel
}] ${
(parameter) message: string
message
}`)
34
})
35
}
36
})
37
)
38
39
class
class Database
Database
extends
import Context
Context
.
const Tag: <"Database">(id: "Database") => <Self, Shape>() => Context.TagClass<Self, "Database", Shape> namespace Tag
Tag
("Database")<
40
class Database
Database
,
41
{ readonly
(property) query: (sql: string) => Effect.Effect<unknown>
query
: (
(parameter) sql: string
sql
: string) =>
import Effect
Effect
.
interface Effect<out A, out E = never, out R = never> namespace Effect

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.

Effect
<unknown> }
42
>() {}
43
44
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.

effect
(
45
class Database
Database
,
46
import Effect
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)
gen
(function* () {
47
const
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
= yield*
class Config
Config
48
const
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
= yield*
class Logger
Logger
49
return {
50
(property) query: (sql: string) => Effect.Effect<{ result: string; }, never, never>
query
: (
(parameter) sql: string
sql
: string) =>
51
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, { result: string; }>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, { ...; }, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
52
yield*
const logger: { readonly log: (message: string) => Effect.Effect<void>; }
logger
.
(property) log: (message: string) => Effect.Effect<void>
log
(`Executing query: ${
(parameter) sql: string
sql
}`)
53
const {
const connection: string
connection
} = yield*
const config: { readonly getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }>; }
config
.
(property) getConfig: Effect.Effect<{ readonly logLevel: string; readonly connection: string; }, never, never>
getConfig
54
return {
(property) result: string
result
: `Results from ${
const connection: string
connection
}` }
55
})
56
}
57
})
58
)
59
60
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.

merge
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
,
const LoggerLive: Layer.Layer<Logger, never, Config>
LoggerLive
)
61
62
const
const MainLive: Layer.Layer<Database, never, never>
MainLive
=
const DatabaseLive: Layer.Layer<Database, never, Config | Logger>
DatabaseLive
.
(method) 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
(
63
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.

provide
(
const AppConfigLive: Layer.Layer<Config | Logger, never, Config>
AppConfigLive
),
64
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.

provide
(
const ConfigLive: Layer.Layer<Config, never, never>
ConfigLive
)
65
)
66
67
const
const program: Effect.Effect<unknown, never, Database>
program
=
import Effect
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)
gen
(function* () {
68
const
const database: { readonly query: (sql: string) => Effect.Effect<unknown>; }
database
= yield*
class Database
Database
69
const
const result: unknown
result
= yield*
const database: { readonly query: (sql: string) => Effect.Effect<unknown>; }
database
.
(property) query: (sql: string) => Effect.Effect<unknown>
query
("SELECT * FROM users")
70
return
const result: unknown
result
71
})
72
73
const
const runnable: Effect.Effect<unknown, never, never>
runnable
=
import Effect
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)

Splits the context into two parts, providing one part using the specified layer/context/runtime and leaving the remainder `R0`

provide
(
const program: Effect.Effect<unknown, never, Database>
program
,
const MainLive: Layer.Layer<Database, never, never>
MainLive
)
74
75
import Effect
Effect
.
const runPromise: <unknown, never>(effect: Effect.Effect<unknown, never, never>, options?: { readonly signal?: AbortSignal; } | undefined) => Promise<unknown>

Executes an effect and returns a `Promise` that resolves with the result. Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises. If the effect fails, the returned Promise will be rejected with the error.

runPromise
(
const runnable: Effect.Effect<unknown, never, never>
runnable
).
(method) 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.

then
(
namespace console 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). 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`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js 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: ```js 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 ```

console
.
(method) 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)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js 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()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.

log
)
76
/*
77
Output:
78
[INFO] Executing query: SELECT * FROM users
79
{
80
result: 'Results from mysql://username:password@hostname:port/database_name'
81
}
82
*/