Skip to content

Introduction to Runtime

The Runtime<R> data type represents a Runtime System that can execute effects. To execute any effect, we need a Runtime that includes the necessary requirements for that effect.

A Runtime<R> consists of three main components:

  • a value of type Context<R>
  • a value of type FiberRefs
  • a value of type RuntimeFlags

When we use functions like Effect.run*, we are actually using the default runtime without explicitly mentioning it. These functions are designed as convenient shortcuts for executing our effects using the default runtime.

For instance, in the Runtime module, there is a corresponding Runtime.run*(defaultRuntime) function that is called internally by Effect.run*, e.g. Effect.runSync is simply an alias for Runtime.runSync(defaultRuntime).

The default runtime includes:

  • An empty Context<never>
  • A set of FiberRefs that include the default services
  • A default configuration for RuntimeFlags that enables Interruption and CooperativeYielding

In most cases, using the default runtime is sufficient. However, it can be useful to create a custom runtime to reuse a specific context or configuration. It is common to create a Runtime<R> by initializing a Layer<R, Err, RIn>. This allows for context reuse across execution boundaries, such as in a React App or when executing operations on a server in response to API requests.

When we write an Effect program, we construct an Effect using constructors and combinators. Essentially, we are creating a blueprint of a program. An Effect is merely a data structure that describes the execution of a concurrent program. It represents a tree-like structure that combines various primitives to define what the Effect should do.

However, this data structure itself does not perform any actions; it is solely a description of a concurrent program.

Therefore, it is crucial to understand that when working with a functional effect system like Effect, our code for actions such as printing to the console, reading files, or querying databases is actually building a workflow or blueprint for an application. We are constructing a data structure.

So how does Effect actually run these workflows? This is where the Effect Runtime System comes into play. When we invoke a Runtime.run* function, the Runtime System takes over. First, it creates an empty root Fiber with:

  • The initial context
  • The initial fiberRefs
  • The initial Effect

After the creation of the Fiber, it invokes the Fiber’s runLoop, which follows the instructions described by the Effect and executes them step by step.

To simplify, we can envision the Runtime System as a black box that takes both the effect Effect<A, E, R> and its associated context Context<R>. It runs the effect and returns the result as an Exit<A, E> value.

Effect Runtime

Runtime Systems have a lot of responsibilities:

  1. Execute every step of the blueprint. They have to execute every step of the blueprint in a while loop until it’s done.

  2. Handle unexpected errors. They have to handle unexpected errors, not just the expected ones but also the unexpected ones.

  3. Spawn concurrent fiber. They are actually responsible for the concurrency that effect systems have. They have to spawn a fiber every time we call fork on an effect to spawn off a new fiber.

  4. Cooperatively yield to other fibers. They have to cooperatively yield to other fibers so that fibers that are sort of hogging the spotlight, don’t get to monopolize all the CPU resources.

  5. Ensure finalizers are run appropriately. They have to ensure finalizers are run appropriately at the right point in all circumstances to make sure that resources are closed that clean-up logic is executed. This is the feature that powers Scope and all the other resource-safe constructs in Effect.

  6. Handle asynchronous callback. They have to handle this messy job of dealing with asynchronous callbacks. So we don’t have to deal with async code. When we are using Effect, everything can be interpreted as async or sync out of the box.

Effect provides a default runtime named Runtime.defaultRuntime designed for mainstream usage.

The default runtime provides the minimum capabilities to bootstrap execution of Effect tasks.

Both of the following executions are equivalent:

1
import {
import Effect
Effect
,
import Runtime
Runtime
} from "effect"
2
3
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("Application started!")
4
5
import Effect
Effect
.
const runSync: <void, never>(effect: Effect.Effect<void, never, never>) => void
runSync
(
const program: Effect.Effect<void, never, never>
program
)
6
/*
7
Output:
8
... level=INFO fiber=#0 message="Application started!"
9
*/
10
11
import Runtime
Runtime
.
const runSync: <never>(runtime: Runtime.Runtime<never>) => <A, E>(effect: Effect.Effect<A, E, never>) => A

Executes the effect synchronously throwing in case of errors or async boundaries. This method is effectful and should only be invoked at the edges of your program.

runSync
(
import Runtime
Runtime
.
const defaultRuntime: Runtime.Runtime<never>
defaultRuntime
)(
const program: Effect.Effect<void, never, never>
program
)
12
/*
13
Output:
14
... level=INFO fiber=#0 message="Application started!"
15
*/

Under the hood, Effect.runSync (and the same principle applies to other Effect.run* functions) serves as a convenient shorthand for Runtime.runSync(Runtime.defaultRuntime).

In Effect, runtime configurations are typically inherited from their parent workflows. This means that when we access a runtime configuration or obtain a runtime inside a workflow, we are essentially using the configuration of the parent workflow. However, there are cases where we want to temporarily override the runtime configuration for a specific part of our code. This concept is known as locally scoped runtime configuration. Once the execution of that code region is completed, the runtime configuration reverts to its original settings.

To achieve this, we make use of Effect.provide* functions, which allow us to provide a new runtime configuration to a specific section of our code.

By utilizing the Effect.provide function and providing runtime configuration layers to an Effect workflow, we can easily modify runtime configurations.

Here’s an example:

1
import {
import Logger
Logger
,
import Effect
Effect
} from "effect"
2
3
// Define a configuration layer
4
const
const addSimpleLogger: Layer<never, never, never>
addSimpleLogger
=
import Logger
Logger
.
const replace: <void, void>(self: Logger.Logger<unknown, void>, that: Logger.Logger<unknown, void>) => Layer<never> (+1 overload)
replace
(
5
import Logger
Logger
.
const defaultLogger: Logger.Logger<unknown, void>
defaultLogger
,
6
import Logger
Logger
.
const make: <unknown, void>(log: (options: Logger.Logger<in Message, out Output>.Options<unknown>) => void) => Logger.Logger<unknown, void>

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

make
(({
(parameter) message: unknown
message
}) =>
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
(
(parameter) message: unknown
message
))
7
)
8
9
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
10
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("Application started!")
11
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("Application is about to exit!")
12
})
13
14
import Effect
Effect
.
const runSync: <void, never>(effect: Effect.Effect<void, never, never>) => void
runSync
(
const program: Effect.Effect<void, never, never>
program
)
15
/*
16
Output:
17
timestamp=... level=INFO fiber=#0 message="Application started!"
18
timestamp=... level=INFO fiber=#0 message="Application is about to exit!"
19
*/
20
21
// Overriding the default logger
22
import Effect
Effect
.
const runSync: <void, never>(effect: Effect.Effect<void, never, never>) => void
runSync
(
const program: Effect.Effect<void, never, never>
program
.
(method) Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect
Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

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

provide
(
const addSimpleLogger: Layer<never, never, never>
addSimpleLogger
)))
23
/*
24
Output:
25
Application started!
26
Application is about to exit!
27
*/

In this example, we first create a configuration layer for a simple logger using Logger.replace. Then, we use Effect.provide to provide this configuration to our program, effectively overriding the default logger with the simple logger.

To ensure that the runtime configuration is only applied to a specific part of an Effect application, we should provide the configuration layer exclusively to that particular section, as demonstrated in the following example:

1
import {
import Logger
Logger
,
import Effect
Effect
} from "effect"
2
3
// Define a configuration layer
4
const
const addSimpleLogger: Layer<never, never, never>
addSimpleLogger
=
import Logger
Logger
.
const replace: <void, void>(self: Logger.Logger<unknown, void>, that: Logger.Logger<unknown, void>) => Layer<never> (+1 overload)
replace
(
5
import Logger
Logger
.
const defaultLogger: Logger.Logger<unknown, void>
defaultLogger
,
6
import Logger
Logger
.
const make: <unknown, void>(log: (options: Logger.Logger<in Message, out Output>.Options<unknown>) => void) => Logger.Logger<unknown, void>

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

make
(({
(parameter) message: unknown
message
}) =>
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
(
(parameter) message: unknown
message
))
7
)
8
9
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
10
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("Application started!")
11
yield*
import Effect
Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen
(function* () {
12
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("I'm not going to be logged!")
13
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("I will be logged by the simple logger.").
(method) Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
14
import Effect
Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

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

provide
(
const addSimpleLogger: Layer<never, never, never>
addSimpleLogger
)
15
)
16
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
(
17
"Reset back to the previous configuration, so I won't be logged."
18
)
19
}).
(method) Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect
Effect
.
const provide: <never, never, never>(layer: Layer<never, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, never>> (+9 overloads)

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

provide
(
import Logger
Logger
.
const remove: <void>(logger: Logger.Logger<unknown, void>) => Layer<never>
remove
(
import Logger
Logger
.
const defaultLogger: Logger.Logger<unknown, void>
defaultLogger
)))
20
yield*
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("Application is about to exit!")
21
})
22
23
import Effect
Effect
.
const runSync: <void, never>(effect: Effect.Effect<void, never, never>) => void
runSync
(
const program: Effect.Effect<void, never, never>
program
)
24
/*
25
Output:
26
timestamp=... level=INFO fiber=#0 message="Application started!"
27
I will be logged by the simple logger.
28
timestamp=... level=INFO fiber=#0 message="Application is about to exit!"
29
*/

When developing an Effect application and executing it using Effect.run* functions, the application is automatically run using the default runtime behind the scenes. While we can adjust and customize specific aspects of our Effect application by providing locally scoped configuration layers using Effect.provide operations, there are scenarios where we need to customize the runtime configuration for the entire application from the top level.

In such situations, we can create a top-level runtime by converting a configuration layer into a runtime using the ManagedRuntime.make constructor.

1
import {
import Effect
Effect
,
import ManagedRuntime
ManagedRuntime
,
import Logger
Logger
} from "effect"
2
3
// Define a configuration layer
4
const
const appLayer: Layer<never, never, never>
appLayer
=
import Logger
Logger
.
const replace: <void, void>(self: Logger.Logger<unknown, void>, that: Logger.Logger<unknown, void>) => Layer<never> (+1 overload)
replace
(
5
import Logger
Logger
.
const defaultLogger: Logger.Logger<unknown, void>
defaultLogger
,
6
import Logger
Logger
.
const make: <unknown, void>(log: (options: Logger.Logger<in Message, out Output>.Options<unknown>) => void) => Logger.Logger<unknown, void>

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

make
(({
(parameter) message: unknown
message
}) =>
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
(
(parameter) message: unknown
message
))
7
)
8
9
// Transform the configuration layer into a runtime
10
const
const runtime: ManagedRuntime.ManagedRuntime<never, never>
runtime
=
import ManagedRuntime
ManagedRuntime
.
const make: <never, never>(layer: Layer<never, never, never>, memoMap?: MemoMap | undefined) => ManagedRuntime.ManagedRuntime<never, never>

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

make
(
const appLayer: Layer<never, never, never>
appLayer
)
11
12
const
const program: Effect.Effect<void, never, never>
program
=
import Effect
Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level, which is INFO by default. This function allows logging multiple items at once and can include detailed error information using `Cause` instances. To adjust the log level, use the `Logger.withMinimumLogLevel` function.

log
("Application started!")
13
14
// Execute the program using the custom runtime
15
const runtime: ManagedRuntime.ManagedRuntime<never, never>
runtime
.
(property) ManagedRuntime<never, never>.runSync: <void, never>(effect: Effect.Effect<void, never, never>) => void

Executes the effect synchronously throwing in case of errors or async boundaries. This method is effectful and should only be invoked at the edges of your program.

runSync
(
const program: Effect.Effect<void, never, never>
program
)
16
17
// Cleaning up any resources used by the configuration layer
18
import Effect
Effect
.
const runFork: <void, never>(effect: Effect.Effect<void, never, never>, options?: RunForkOptions) => RuntimeFiber<void, never>
runFork
(
const runtime: ManagedRuntime.ManagedRuntime<never, never>
runtime
.
(property) ManagedRuntime<never, never>.disposeEffect: Effect.Effect<void, never, never>

Dispose of the resources associated with the runtime.

disposeEffect
)
19
/*
20
Output:
21
Application started!
22
*/

In this example, we first create a custom configuration layer called appLayer, which includes modifications to the logger configuration. Next, we transform this configuration layer into a runtime using ManagedRuntime.make. This results in a top-level runtime that encapsulates the desired configuration for the entire Effect application.

By customizing the top-level runtime configuration, we can tailor the behavior of our entire Effect application to meet our specific needs and requirements.

When you utilize a runtime that you pass around, you can use Effect.Tag to define a new tag and simplify access to a service. This incorporates the service shape directly into the static side of the tag class.

You can define a new tag using Effect.Tag as shown below:

1
import {
import Effect
Effect
} from "effect"
2
3
class
class Notifications
Notifications
extends
import Effect
Effect
.
const Tag: <"Notifications">(id: "Notifications") => <Self, Type>() => TagClass<Self, "Notifications", Type> & (Type extends Record<PropertyKey, any> ? Effect.Tag.Proxy<...> : {}) & { ...; } namespace Tag
Tag
("Notifications")<
4
class Notifications
Notifications
,
5
{ readonly
(property) notify: (message: string) => Effect.Effect<void>
notify
: (
(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> }
6
>() {}

In this setup, every field of the service shape is converted into a static property of the Notifications class.

This allows you to access the service shape directly:

1
import {
import Effect
Effect
} from "effect"
2
3
class
class Notifications
Notifications
extends
import Effect
Effect
.
const Tag: <"Notifications">(id: "Notifications") => <Self, Type>() => TagClass<Self, "Notifications", Type> & (Type extends Record<PropertyKey, any> ? Effect.Tag.Proxy<...> : {}) & { ...; } namespace Tag
Tag
("Notifications")<
4
class Notifications
Notifications
,
5
{ readonly
(property) notify: (message: string) => Effect.Effect<void>
notify
: (
(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> }
6
>() {}
7
8
const
const action: Effect.Effect<void, never, Notifications>
action
=
class Notifications
Notifications
.
(property) notify: (message: string) => Effect.Effect<void, never, Notifications>
notify
("Hello, world!")

As you can see, action depends on Notifications, but this isn’t a problem because you can later construct a Layer that provides Notifications and build a ManagedRuntime with it.

The ManagedRuntime simplifies the integration of services and layers with other frameworks or tools, particularly in environments where Effect is not the primary framework and access to the main entry point is restricted.

For instance, ManagedRuntime can be particularly useful in environments like React or other frameworks where control over the main application entry point is limited. Here’s how you can use ManagedRuntime to manage service lifecycle within an external framework:

1
import {
import Effect
Effect
,
import ManagedRuntime
ManagedRuntime
,
import Layer
Layer
,
import Console
Console
} from "effect"
2
3
class
class Notifications
Notifications
extends
import Effect
Effect
.
const Tag: <"Notifications">(id: "Notifications") => <Self, Type>() => TagClass<Self, "Notifications", Type> & (Type extends Record<PropertyKey, any> ? Effect.Tag.Proxy<...> : {}) & { ...; } namespace Tag
Tag
("Notifications")<
4
class Notifications
Notifications
,
5
{ readonly
(property) notify: (message: string) => Effect.Effect<void>
notify
: (
(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> }
6
>() {
7
static
(property) Notifications.Live: Layer.Layer<Notifications, never, never>
Live
=
import Layer
Layer
.
const succeed: <typeof Notifications>(tag: typeof Notifications, resource: { readonly notify: (message: string) => Effect.Effect<void>; }) => Layer.Layer<Notifications, never, never> (+1 overload)

Constructs a layer from the specified value.

succeed
(this, {
8
(property) notify: (message: string) => Effect.Effect<void>
notify
: (
(parameter) message: string
message
) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>
log
(
(parameter) message: string
message
)
9
})
10
}
11
12
// Example entry point for an external framework
13
async function
function main(): Promise<void>
main
() {
14
const
const runtime: ManagedRuntime.ManagedRuntime<Notifications, never>
runtime
=
import ManagedRuntime
ManagedRuntime
.
const make: <Notifications, never>(layer: Layer.Layer<Notifications, never, never>, memoMap?: Layer.MemoMap | undefined) => ManagedRuntime.ManagedRuntime<Notifications, never>

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

make
(
class Notifications
Notifications
.
(property) Notifications.Live: Layer.Layer<Notifications, never, never>
Live
)
15
await
const runtime: ManagedRuntime.ManagedRuntime<Notifications, never>
runtime
.
(property) ManagedRuntime<Notifications, never>.runPromise: <void, never>(effect: Effect.Effect<void, never, Notifications>, options?: { readonly signal?: AbortSignal | undefined; } | undefined) => Promise<void>

Runs the `Effect`, returning a JavaScript `Promise` that will be resolved with the value of the effect once the effect has been executed, or will be rejected with the first error or exception throw by the effect. This method is effectful and should only be used at the edges of your program.

runPromise
(
class Notifications
Notifications
.
(property) notify: (message: string) => Effect.Effect<void, never, Notifications>
notify
("Hello, world!"))
16
await
const runtime: ManagedRuntime.ManagedRuntime<Notifications, never>
runtime
.
(property) ManagedRuntime<Notifications, never>.dispose: () => Promise<void>

Dispose of the resources associated with the runtime.

dispose
()
17
}