Configuration
Configuration is an essential aspect of any cloud-native application. Effect simplifies the process of managing configuration by offering a convenient interface for configuration providers.
The configuration front-end in Effect enables ecosystem libraries and applications to specify their configuration requirements in a declarative manner. It offloads the complex tasks to a ConfigProvider
, which can be supplied by third-party libraries.
Effect comes bundled with a straightforward default ConfigProvider
that retrieves configuration data from environment variables. This default provider can be used during development or as a starting point before transitioning to more advanced configuration providers.
To make our application configurable, we need to understand three essential elements:
-
Config Description: We describe the configuration data using an instance of
Config<A>
. If the configuration data is simple, such as astring
,number
, orboolean
, we can use the built-in functions provided by theConfig
module. For more complex data types like HostPort, we can combine primitive configs to create a custom configuration description. -
Config Frontend: We utilize the instance of
Config<A>
to load the configuration data described by the instance (aConfig
is, in itself, an effect). This process leverages the currentConfigProvider
to retrieve the configuration. -
Config Backend: The
ConfigProvider
serves as the underlying engine that manages the configuration loading process. Effect comes with a default config provider as part of its default services. This default provider reads the configuration data from environment variables. If we want to use a custom config provider, we can utilize theLayer.setConfigProvider
layer to configure the Effect runtime accordingly.
Effect provides several built-in types for configuration values, which you can use right out of the box:
Type | Description |
---|---|
string | Constructs a config for a string value. |
number | Constructs a config for a float value. |
boolean | Constructs a config for a boolean value. |
integer | Constructs a config for an integer value. |
date | Constructs a config for a date value. |
literal | Constructs a config for a literal (*) value. |
logLevel | Constructs a config for a LogLevel value. |
duration | Constructs a config for a duration value. |
redacted | Constructs a config for a secret value. |
(*) string | number | boolean | null | bigint
Example (Using Primitives)
Here’s an example of loading a basic configuration using environment variables for HOST
and PORT
:
1import { import Effect
Effect, import Config
Config } from "effect"2
3// Define a program that loads HOST and PORT configuration4const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<string, ConfigError, never>> | YieldWrap<Effect.Effect<number, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {5 // Load the HOST from environment variables6 const const host: string
host = yield* import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("HOST")7 // Load the PORT as a number8 const const port: number
port = yield* import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("PORT")9
10 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(`Application started: ${const host: string
host}:${const port: number
port}`)11})12
13import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
If you run this without setting the required environment variables:
npx tsx primitives.ts
you’ll see an error indicating the missing configuration:
[Error: (Missing data at HOST: "Expected HOST to exist in the process context")] { name: '(FiberFailure) Error', [Symbol(effect/Runtime/FiberFailure)]: Symbol(effect/Runtime/FiberFailure), [Symbol(effect/Runtime/FiberFailure/Cause)]: { _tag: 'Fail', error: { _op: 'MissingData', path: [ 'HOST' ], message: 'Expected HOST to exist in the process context' } }}
To run the program successfully, set the environment variables as shown below:
HOST=localhost PORT=8080 npx tsx primitives.ts
Output:
Application started: localhost:8080
Sometimes, you may encounter situations where an environment variable is missing, leading to an incomplete configuration. To address this, Effect provides the Config.withDefault
function, which allows you to specify a default value. This fallback ensures that your application continues to function even if a required environment variable is not set.
Example (Using Default Values)
1import { import Effect
Effect, import Config
Config } from "effect"2
3const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<string, ConfigError, never>> | YieldWrap<Effect.Effect<number, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {4 const const host: string
host = yield* import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("HOST")5 // Use default 8080 if PORT is not set6 const const port: number
port = yield* import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("PORT").(method) Pipeable.pipe<Config.Config<number>, Config.Config<number>>(this: Config.Config<number>, ab: (_: Config.Config<number>) => Config.Config<number>): Config.Config<...> (+21 overloads)
pipe(import Config
Config.const withDefault: <8080>(def: 8080) => <A>(self: Config.Config<A>) => Config.Config<8080 | A> (+1 overload)
Returns a config that describes the same structure as this one, but has the
specified default value in case the information cannot be found.
withDefault(8080))7 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(`Application started: ${const host: string
host}:${const port: number
port}`)8})9
10import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
Running this program with only the HOST
environment variable set:
HOST=localhost npx tsx defaults.ts
produces the following output:
Application started: localhost:8080
In this case, even though the PORT
environment variable is not set, the program continues to run, using the default value of 8080
for the port. This ensures that the application remains functional without requiring every configuration to be explicitly provided.
Effect provides several built-in constructors that allow you to define and manipulate configurations. These constructors take a Config
as input and produce another Config
, enabling more complex configuration structures.
Here are some of the key constructors:
Constructor | Description |
---|---|
array | Constructs a configuration for an array of values. |
chunk | Constructs a configuration for a sequence of values. |
option | Returns an optional configuration. If the data is missing, the result will be None ; otherwise, it will be Some . |
repeat | Describes a sequence of values, each following the structure of the given config. |
hashSet | Constructs a configuration for a set of values. |
hashMap | Constructs a configuration for a key-value map. |
Additionally, there are three special constructors for specific use cases:
Constructor | Description |
---|---|
succeed | Constructs a config that contains a predefined value. |
fail | Constructs a config that fails with the specified error message. |
all | Combines multiple configurations into a tuple, struct, or argument list. |
Example (Using array
Constructor)
The following example demonstrates how to load an environment variable as an array of strings using the Config.array
constructor.
1import { import Effect
Effect, import Config
Config } from "effect"2
3const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<string[], ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<string[], ConfigError, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {4 // Load array from env var MY_ARRAY5 const const config: string[]
config = yield* import Config
Config.const array: <string>(config: Config.Config<string>, name?: string) => Config.Config<string[]>
Constructs a config for an array of values.
array(import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string(), "MY_ARRAY")6 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 config: string[]
config)7})8
9import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
If we run this program with the following environment variable:
MY_ARRAY=a,b,c npx tsx array.ts
The output will be:
[ 'a', 'b', 'c' ]
This shows how the array
constructor converts a comma-separated string from an environment variable into an array of values, making configuration handling more flexible.
Effect provides several built-in operators to work with configurations, allowing you to manipulate and transform them according to your needs.
These operators enable you to modify configurations or validate their values:
Operator | Description |
---|---|
validate | Ensures that a configuration meets certain criteria, returning a validation error if it does not. |
map | Transforms the values of a configuration using a provided function. |
mapAttempt | Similar to map , but catches any errors thrown by the function and converts them into validation errors. |
mapOrFail | Like map , but the function can fail. If it does, the result is a validation error. |
Example (Using validate
Operator)
1import { import Effect
Effect, import Config
Config } from "effect"2
3const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<string, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<string, ConfigError, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {4 // Load the NAME environment variable and validate its length5 const const config: string
config = yield* import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("NAME").(method) Pipeable.pipe<Config.Config<string>, Config.Config<string>>(this: Config.Config<string>, ab: (_: Config.Config<string>) => Config.Config<string>): Config.Config<...> (+21 overloads)
pipe(6 import Config
Config.const validate: <string>(options: {
readonly message: string;
readonly validation: Predicate<string>;
}) => (self: Config.Config<string>) => Config.Config<string> (+3 overloads)
Returns a config that describes the same structure as this one, but which
performs validation during loading.
validate({7 (property) message: string
message: "Expected a string at least 4 characters long",8 (property) validation: Predicate<string>
validation: ((parameter) s: string
s) => (parameter) s: string
s.(property) String.length: number
Returns the length of a String object.
length >= 49 })10 )11 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 config: string
config)12})13
14import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
If we run this program with an invalid NAME
value:
NAME=foo npx tsx validate.ts
The output will be:
[Error: (Invalid data at NAME: "Expected a string at least 4 characters long")] { name: '(FiberFailure) Error', [Symbol(effect/Runtime/FiberFailure)]: Symbol(effect/Runtime/FiberFailure), [Symbol(effect/Runtime/FiberFailure/Cause)]: { _tag: 'Fail', error: { _op: 'InvalidData', path: [ 'NAME' ], message: 'Expected a string at least 4 characters long' } }}
Fallback operators are useful when you want to provide alternative configurations in case of errors or missing data. These operators ensure that your program can still run even if some configuration values are unavailable.
Operator | Description |
---|---|
orElse | Attempts to use the primary config first. If it fails or is missing, it falls back to another config. |
orElseIf | Similar to orElse , but it switches to the fallback config only if the error matches a condition. |
Example (Using orElse
for Fallback)
In this example, the program requires two configuration values: A
and B
. We set up two configuration providers, each containing only one of the required values. Using the orElse
operator, we combine these providers so the program can retrieve both A
and B
.
1import { import Config
Config, import ConfigProvider
ConfigProvider, import Effect
Effect, import Layer
Layer } from "effect"2
3// A program that requires two configurations: A and B4const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<string, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<string, ConfigError, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {5 const const A: string
A = yield* import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("A") // Retrieve config A6 const const B: string
B = yield* import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("B") // Retrieve config B7 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(`A: ${const A: string
A}, B: ${const B: string
B}`)8})9
10// First provider has A but is missing B11const const provider1: ConfigProvider.ConfigProvider
provider1 = import ConfigProvider
ConfigProvider.const fromMap: (map: Map<string, string>, config?: Partial<ConfigProvider.ConfigProvider.FromMapConfig>) => ConfigProvider.ConfigProvider
Constructs a ConfigProvider using a map and the specified delimiter string,
which determines how to split the keys in the map into path segments.
fromMap(new var Map: MapConstructor
new <string, string>(iterable?: Iterable<readonly [string, string]> | null | undefined) => Map<string, string> (+3 overloads)
Map([["A", "A"]]))12
13// Second provider has B but is missing A14const const provider2: ConfigProvider.ConfigProvider
provider2 = import ConfigProvider
ConfigProvider.const fromMap: (map: Map<string, string>, config?: Partial<ConfigProvider.ConfigProvider.FromMapConfig>) => ConfigProvider.ConfigProvider
Constructs a ConfigProvider using a map and the specified delimiter string,
which determines how to split the keys in the map into path segments.
fromMap(new var Map: MapConstructor
new <string, string>(iterable?: Iterable<readonly [string, string]> | null | undefined) => Map<string, string> (+3 overloads)
Map([["B", "B"]]))15
16// Use `orElse` to fall back from provider1 to provider217const const layer: Layer.Layer<never, never, never>
layer = import Layer
Layer.const setConfigProvider: (configProvider: ConfigProvider.ConfigProvider) => Layer.Layer<never>
Sets the current `ConfigProvider`.
setConfigProvider(18 const provider1: ConfigProvider.ConfigProvider
provider1.(method) Pipeable.pipe<ConfigProvider.ConfigProvider, ConfigProvider.ConfigProvider>(this: ConfigProvider.ConfigProvider, ab: (_: ConfigProvider.ConfigProvider) => ConfigProvider.ConfigProvider): ConfigProvider.ConfigProvider (+21 overloads)
pipe(import ConfigProvider
ConfigProvider.const orElse: (that: LazyArg<ConfigProvider.ConfigProvider>) => (self: ConfigProvider.ConfigProvider) => ConfigProvider.ConfigProvider (+1 overload)
Returns a new config provider that preferentially loads configuration data
from this one, but which will fall back to the specified alternate provider
if there are any issues loading the configuration from this provider.
orElse(() => const provider2: ConfigProvider.ConfigProvider
provider2))19)20
21import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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(import Effect
Effect.const provide: <void, ConfigError, never, never, never, never>(self: Effect.Effect<void, ConfigError, never>, layer: Layer.Layer<never, never, never>) => Effect.Effect<...> (+9 overloads)
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<void, ConfigError, never>
program, const layer: Layer.Layer<never, never, never>
layer))
If we run this program:
npx tsx orElse.ts
The output will be:
A: A, B: B
Effect allows you to define configurations for custom types by combining primitive configs using Config
operators (such as zip
, orElse
, map
) and constructors (like array
, hashSet
).
For example, let’s create a HostPort
class, which has two fields: host
and port
.
1class class HostPort
HostPort {2 constructor(readonly (property) HostPort.host: string
host: string, readonly (property) HostPort.port: number
port: number) {}3 get (getter) HostPort.url: string
url() {4 return `${this.(property) HostPort.host: string
host}:${this.(property) HostPort.port: number
port}`5 }6}
To define a configuration for this custom type, we can combine primitive configs for string
and number
:
1import { import Config
Config } from "effect"2
3class class HostPort
HostPort {4 constructor(readonly (property) HostPort.host: string
host: string, readonly (property) HostPort.port: number
port: number) {}5 get (getter) HostPort.url: string
url() {6 return `${this.(property) HostPort.host: string
host}:${this.(property) HostPort.port: number
port}`7 }8}9
10// Combine the configuration for 'HOST' and 'PORT'11const const both: Config.Config<[string, number]>
both = import Config
Config.const all: <readonly [Config.Config<string>, Config.Config<number>]>(arg: readonly [Config.Config<string>, Config.Config<number>]) => Config.Config<[string, number]>
Constructs a config from a tuple / struct / arguments of configs.
all([import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("HOST"), import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("PORT")])12
13// Map the configuration values into a HostPort instance14const const config: Config.Config<HostPort>
config = import Config
Config.const map: <[string, number], HostPort>(self: Config.Config<[string, number]>, f: (a: [string, number]) => HostPort) => Config.Config<HostPort> (+1 overload)
Returns a config whose structure is the same as this one, but which produces
a different value, constructed using the specified function.
map(15 const both: Config.Config<[string, number]>
both,16 ([(parameter) host: string
host, (parameter) port: number
port]) => new constructor HostPort(host: string, port: number): HostPort
HostPort((parameter) host: string
host, (parameter) port: number
port)17)
In this example, Config.all(configs)
combines two primitive configurations, Config<string>
and Config<number>
, into a Config<[string, number]>
. The Config.map
operator is then used to transform these values into an instance of the HostPort
class.
Example (Using Custom Configuration)
1import { import Effect
Effect, import Config
Config } from "effect"2
3class class HostPort
HostPort {4 constructor(readonly (property) HostPort.host: string
host: string, readonly (property) HostPort.port: number
port: number) {}5 get (getter) HostPort.url: string
url() {6 return `${this.(property) HostPort.host: string
host}:${this.(property) HostPort.port: number
port}`7 }8}9
10// Combine the configuration for 'HOST' and 'PORT'11const const both: Config.Config<[string, number]>
both = import Config
Config.const all: <readonly [Config.Config<string>, Config.Config<number>]>(arg: readonly [Config.Config<string>, Config.Config<number>]) => Config.Config<[string, number]>
Constructs a config from a tuple / struct / arguments of configs.
all([import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("HOST"), import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("PORT")])12
13// Map the configuration values into a HostPort instance14const const config: Config.Config<HostPort>
config = import Config
Config.const map: <[string, number], HostPort>(self: Config.Config<[string, number]>, f: (a: [string, number]) => HostPort) => Config.Config<HostPort> (+1 overload)
Returns a config whose structure is the same as this one, but which produces
a different value, constructed using the specified function.
map(15 const both: Config.Config<[string, number]>
both,16 ([(parameter) host: string
host, (parameter) port: number
port]) => new constructor HostPort(host: string, port: number): HostPort
HostPort((parameter) host: string
host, (parameter) port: number
port)17)18
19// Main program that reads configuration and starts the application20const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<HostPort, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<HostPort, ConfigError, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {21 const const hostPort: HostPort
hostPort = yield* const config: Config.Config<HostPort>
config22 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(`Application started: ${const hostPort: HostPort
hostPort.(property) HostPort.url: string
url}`)23})24
25import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
When you run this program, it will try to retrieve the values for HOST
and PORT
from your environment variables:
HOST=localhost PORT=8080 npx tsx App.ts
If successful, it will print:
Application started: localhost:8080
We’ve seen how to define configurations at the top level, whether for primitive or custom types. In some cases, though, you might want to structure your configurations in a more nested way, organizing them under common namespaces for clarity and manageability.
For instance, consider the following ServiceConfig
type:
1class class ServiceConfig
ServiceConfig {2 constructor(3 readonly (property) ServiceConfig.host: string
host: string,4 readonly (property) ServiceConfig.port: number
port: number,5 readonly (property) ServiceConfig.timeout: number
timeout: number6 ) {}7 get (getter) ServiceConfig.url: string
url() {8 return `${this.(property) ServiceConfig.host: string
host}:${this.(property) ServiceConfig.port: number
port}`9 }10}
If you were to use this configuration in your application, it would expect the HOST
, PORT
, and TIMEOUT
environment variables at the top level. But in many cases, you may want to organize configurations under a shared namespace—for example, grouping HOST
and PORT
under a SERVER
namespace, while keeping TIMEOUT
at the root.
To do this, you can use the Config.nested
operator, which allows you to nest configuration values under a specific namespace. Let’s update the previous example to reflect this:
1import { import Config
Config } from "effect"2
3class class ServiceConfig
ServiceConfig {4 constructor(5 readonly (property) ServiceConfig.host: string
host: string,6 readonly (property) ServiceConfig.port: number
port: number,7 readonly (property) ServiceConfig.timeout: number
timeout: number8 ) {}9 get (getter) ServiceConfig.url: string
url() {10 return `${this.(property) ServiceConfig.host: string
host}:${this.(property) ServiceConfig.port: number
port}`11 }12}13
14const const serverConfig: Config.Config<[string, number]>
serverConfig = import Config
Config.const all: <readonly [Config.Config<string>, Config.Config<number>]>(arg: readonly [Config.Config<string>, Config.Config<number>]) => Config.Config<[string, number]>
Constructs a config from a tuple / struct / arguments of configs.
all([15 import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("HOST"),16 import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("PORT")17])18
19const const serviceConfig: Config.Config<ServiceConfig>
serviceConfig = import Config
Config.const map: <[[string, number], number], ServiceConfig>(self: Config.Config<[[string, number], number]>, f: (a: [[string, number], number]) => ServiceConfig) => Config.Config<...> (+1 overload)
Returns a config whose structure is the same as this one, but which produces
a different value, constructed using the specified function.
map(20 import Config
Config.const all: <readonly [Config.Config<[string, number]>, Config.Config<number>]>(arg: readonly [Config.Config<[string, number]>, Config.Config<number>]) => Config.Config<[[string, number], number]>
Constructs a config from a tuple / struct / arguments of configs.
all([21 // Read 'HOST' and 'PORT' from 'SERVER' namespace22 import Config
Config.const nested: <[string, number]>(self: Config.Config<[string, number]>, name: string) => Config.Config<[string, number]> (+1 overload)
Returns a config that has this configuration nested as a property of the
specified name.
nested(const serverConfig: Config.Config<[string, number]>
serverConfig, "SERVER"),23 // Read 'TIMEOUT' from the root namespace24 import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("TIMEOUT")25 ]),26 ([[(parameter) host: string
host, (parameter) port: number
port], (parameter) timeout: number
timeout]) => new constructor ServiceConfig(host: string, port: number, timeout: number): ServiceConfig
ServiceConfig((parameter) host: string
host, (parameter) port: number
port, (parameter) timeout: number
timeout)27)
Now, if you run your application with this configuration setup, it will look for the following environment variables:
SERVER_HOST
for the host valueSERVER_PORT
for the port valueTIMEOUT
for the timeout value
This structured approach keeps your configuration more organized, especially when dealing with multiple services or complex applications.
When testing services, there are times when you need to provide specific configurations for your tests. To simulate this, it’s useful to mock the configuration backend that reads these values.
You can achieve this using the ConfigProvider.fromMap
constructor. This method allows you to create a configuration provider from a Map<string, string>
, where the map represents the configuration data. You can then use this mock provider in place of the default one by calling Layer.setConfigProvider
. This function returns a Layer
that can override the default configuration for your tests.
Example (Mocking a Config Provider for Testing)
1import { import Config
Config, import ConfigProvider
ConfigProvider, import Layer
Layer, import Effect
Effect } from "effect"2
3class class HostPort
HostPort {4 constructor(readonly (property) HostPort.host: string
host: string, readonly (property) HostPort.port: number
port: number) {}5 get (getter) HostPort.url: string
url() {6 return `${this.(property) HostPort.host: string
host}:${this.(property) HostPort.port: number
port}`7 }8}9
10const const config: Config.Config<HostPort>
config = import Config
Config.const map: <[string, number], HostPort>(self: Config.Config<[string, number]>, f: (a: [string, number]) => HostPort) => Config.Config<HostPort> (+1 overload)
Returns a config whose structure is the same as this one, but which produces
a different value, constructed using the specified function.
map(11 import Config
Config.const all: <readonly [Config.Config<string>, Config.Config<number>]>(arg: readonly [Config.Config<string>, Config.Config<number>]) => Config.Config<[string, number]>
Constructs a config from a tuple / struct / arguments of configs.
all([import Config
Config.const string: (name?: string) => Config.Config<string>
Constructs a config for a string value.
string("HOST"), import Config
Config.const number: (name?: string) => Config.Config<number>
Constructs a config for a float value.
number("PORT")]),12 ([(parameter) host: string
host, (parameter) port: number
port]) => new constructor HostPort(host: string, port: number): HostPort
HostPort((parameter) host: string
host, (parameter) port: number
port)13)14
15const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<HostPort, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<HostPort, ConfigError, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {16 const const hostPort: HostPort
hostPort = yield* const config: Config.Config<HostPort>
config17 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(`Application started: ${const hostPort: HostPort
hostPort.(property) HostPort.url: string
url}`)18})19
20// Create a mock config provider using a map with test data21const const mockConfigProvider: ConfigProvider.ConfigProvider
mockConfigProvider = import ConfigProvider
ConfigProvider.const fromMap: (map: Map<string, string>, config?: Partial<ConfigProvider.ConfigProvider.FromMapConfig>) => ConfigProvider.ConfigProvider
Constructs a ConfigProvider using a map and the specified delimiter string,
which determines how to split the keys in the map into path segments.
fromMap(22 new var Map: MapConstructor
new <string, string>(iterable?: Iterable<readonly [string, string]> | null | undefined) => Map<string, string> (+3 overloads)
Map([23 ["HOST", "localhost"],24 ["PORT", "8080"]25 ])26)27
28// Override the default config provider with the mock provider29const const layer: Layer.Layer<never, never, never>
layer = import Layer
Layer.const setConfigProvider: (configProvider: ConfigProvider.ConfigProvider) => Layer.Layer<never>
Sets the current `ConfigProvider`.
setConfigProvider(const mockConfigProvider: ConfigProvider.ConfigProvider
mockConfigProvider)30
31// Run the program using the mock config provider32import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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(import Effect
Effect.const provide: <void, ConfigError, never, never, never, never>(self: Effect.Effect<void, ConfigError, never>, layer: Layer.Layer<never, never, never>) => Effect.Effect<...> (+9 overloads)
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<void, ConfigError, never>
program, const layer: Layer.Layer<never, never, never>
layer))33// Output: Application started: localhost:8080
This approach helps you create isolated tests that don’t rely on external environment variables, ensuring your tests run consistently with mock configurations.
The Config.redacted
function is used to handle sensitive information safely. It parses the configuration value and wraps it in a Redacted<string>
, a specialized data type designed to protect secrets.
When you log a Redacted
value using console.log
, the actual content remains hidden, providing an extra layer of security. To access the real value, you must explicitly use Redacted.value
.
Example (Handling Redacted Values)
1import { import Effect
Effect, import Config
Config, import Redacted
Redacted } from "effect"2
3const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Redacted.Redacted<string>, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {4 const const redacted: Redacted.Redacted<string>
redacted = yield* import Config
Config.const redacted: (name?: string) => Config.Config<Redacted.Redacted>
Constructs a config for a redacted value.
redacted("API_KEY")5
6 // Log the redacted value, which won't reveal the actual secret7 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(`Console output: ${const redacted: Redacted.Redacted<string>
redacted}`)8
9 // Access the real value using Redacted.value and log it10 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(`Actual value: ${import Redacted
Redacted.const value: <string>(self: Redacted.Redacted<string>) => string
Retrieves the original value from a `Redacted` instance. Use this function
with caution, as it exposes the sensitive data.
value(const redacted: Redacted.Redacted<string>
redacted)}`)11})12
13import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
When this program is executed:
API_KEY=my-api-key tsx redacted.ts
The output will look like this:
Console output: <redacted>Actual value: my-api-key
As shown, when logging the Redacted
value using console.log
, the output is <redacted>
, ensuring that sensitive data remains concealed. However, by using Redacted.value
, the true value ("my-api-key"
) can be accessed and displayed, providing controlled access to the secret.
Deprecated since version 3.3.0: Please use Config.redacted for handling sensitive information going forward.
The Config.secret
function was previously used to secure sensitive information in a similar way to Config.redacted
. It wraps configuration values in a Secret
type, which also conceals details when logged but allows access via Secret.value
.
Example (Using Deprecated Config.secret
)
1import { import Effect
Effect, import Config
Config, import Secret
Secret } from "effect"2
3const const program: Effect.Effect<void, ConfigError, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<Secret.Secret, ConfigError, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<Secret.Secret, ConfigError, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {4 const const secret: Secret.Secret
secret = yield* import Config
Config.const secret: (name?: string) => Config.Config<Secret.Secret>
Constructs a config for a secret value.
secret("API_KEY")5
6 // Log the secret value, which won't reveal the actual secret7 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(`Console output: ${const secret: Secret.Secret
secret}`)8
9 // Access the real value using Secret.value and log it10 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(`Actual value: ${import Secret
Secret.const value: (self: Secret.Secret) => string
value(const secret: Secret.Secret
secret)}`)11})12
13import Effect
Effect.const runPromise: <void, ConfigError>(effect: Effect.Effect<void, ConfigError, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<...>
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 program: Effect.Effect<void, ConfigError, never>
program)
When this program is executed:
API_KEY=my-api-key tsx secret.ts
The output will look like this:
Console output: Secret(<redacted>)Actual value: my-api-key