(
config?: FieldRecord | ConfigField<unknown>
): Layer.Layer<DynamicConfigStore>Provide the override store and a ConfigProvider (reads swaps first, then the real
environment). The setByKey allowlist is the process-wide SwappableRegistry
(every globalSwappable) plus — when you pass config (a bag from make /
extend, or a lone swappable field) — that config's own swappable keys, scoped to
this provision. Provide once, at or above any scope that reads or swaps; scoping (Effect.scoped)
and forked fibers inherit it. Separate runtimes get their own store.
export const const layer: (
config?: FieldRecord | ConfigField<unknown>
) => Layer.Layer<DynamicConfigStore>
Provide the override store and a ConfigProvider (reads swaps first, then the real
environment). The
setByKey
allowlist is the process-wide
SwappableRegistry
(every
globalSwappable
) plus — when you pass config (a bag from
make
/
extend
, or a lone
swappable
field) — that config's own swappable keys, scoped to
this provision. Provide once, at or above any scope that reads or swaps; scoping (Effect.scoped)
and forked fibers inherit it. Separate runtimes get their own store.
layer = (
config: FieldRecord | ConfigField<unknown>config?: type FieldRecord = {
[x: string]: ConfigField<unknown>
}
FieldRecord | interface ConfigField<A>A yieldable config field. yield* field reads its underlying Config
through the ambient provider. Read-only on its own;
SwappableField
adds the control methods — so swappability is a structural distinction, not a
stored marker flag.
ConfigField<unknown>,
): import LayerLayer.interface Layer<in ROut, out E = never, out RIn = never>A Layer describes how to build one or more services for dependency injection.
When to use
Use to model construction of application services for dependency injection,
especially when services have dependencies, can fail during construction, or
need scoped setup and release.
Details
A Layer<ROut, E, RIn> represents ROut as the services this layer
provides, E as the possible errors during layer construction, and RIn as
the services this layer requires as dependencies.
Layer<class DynamicConfigStoreclass DynamicConfigStore {
key: Identifier;
Service: {
setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>;
unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>;
changedKeys: Stream.Stream<ReadonlyArray<string>>;
allowed: ReadonlyMap<string, Config.Config<unknown>>;
};
}
Shared override store. Provided by
layer
; written by a swappable
field's .set / .reset (and
setByKey
), and read (as a
ConfigProvider) by every Config.
DynamicConfigStore> =>
import LayerLayer.const unwrap: <A, E1, R1, E, R>(
self: Effect<Layer<A, E1, R1>, E, R>
) => Layer<
A,
E | E1,
R1 | Exclude<R, Scope.Scope>
>
Unwraps a Layer from an Effect, flattening the nested structure.
When to use
Use when you have an Effect that produces a Layer and you want to
use that layer directly.
Details
The resulting Layer will have the combined error and dependency types from
both the outer Effect and the inner Layer.
Example (Unwrapping an effectful layer)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const layerEffect = Effect.succeed(
Layer.succeed(Database, { query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result")) })
)
const unwrappedLayer = Layer.unwrap(layerEffect)
unwrap(
import EffectEffect.const gen: {
<Eff extends Effect<any, any, any>, AEff>(
f: () => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
options: { readonly self: Self },
f: (this: Self) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer E, infer _R>
]
? E
: never,
[Eff] extends [never]
? never
: [Eff] extends [
Effect<infer _A, infer _E, infer R>
]
? R
: never
>
}
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
Example (Sequencing effects with generators)
import { Data, Effect } from "effect"
class DiscountRateError extends Data.TaggedError("DiscountRateError")<{}> {}
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, DiscountRateError> =>
discountRate === 0
? Effect.fail(new DiscountRateError())
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function*() {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})
gen(function* () {
const const overrides: SubscriptionRef.SubscriptionRef<
Map<string, string>
>
const overrides: {
value: A;
semaphore: Semaphore.Semaphore;
pubsub: PubSub.PubSub<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
overrides = yield* import SubscriptionRefSubscriptionRef.const make: <A>(
value: A
) => Effect.Effect<SubscriptionRef<A>>
Constructs a new SubscriptionRef from an initial value.
When to use
Use to create a SubscriptionRef when consumers need to read the latest
value and subscribe to every update.
Details
The initial value is published during construction, so changes starts new
subscribers with that value before future updates.
make(new var Map: MapConstructor
new <string, string>(iterable?: Iterable<readonly [string, string]> | null | undefined) => Map<string, string> (+3 overloads)
Map<string, string>());
const const provider: ConfigProvider.ConfigProviderconst provider: {
load: (path: Path) => Effect.Effect<Node | undefined, SourceError>;
state: ProviderState;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
provider = import ConfigProviderConfigProvider.function make(
get: (
path: Path
) => Effect.Effect<
Node | undefined,
SourceError
>
): ConfigProvider
Creates a ConfigProvider from a raw lookup function.
When to use
Use when implementing a provider backed by a custom store, such as a
database, remote API, or in-memory map.
Details
The get callback receives a Path and must return
Effect<Node | undefined, SourceError>. Return undefined when the path
does not exist; fail with SourceError only for actual I/O errors.
Example (Creating a simple in-memory provider)
import { ConfigProvider, Effect } from "effect"
const data: Record<string, string> = {
host: "localhost",
port: "5432"
}
const provider = ConfigProvider.make((path) => {
const key = path.join(".")
const value = data[key]
return Effect.succeed(
value !== undefined ? ConfigProvider.makeValue(value) : undefined
)
})
make((path: ConfigProvider.Path(parameter) path: {
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<string | number>>): Array<string | number>; (...items: Array<string | number | ConcatArray<string | number>>): Array<string | number> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<string | number>;
indexOf: (searchElement: string | number, fromIndex?: number) => number;
lastIndexOf: (searchElement: string | number, fromIndex?: number) => number;
every: { (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) =>…;
some: (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: string | number, index: number, array: ReadonlyArray<string | number>) => void, thisArg?: any) => void;
map: (callbackfn: (value: string | number, index: number, array: ReadonlyArray<string | number>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => value is S, thisArg?: any): Array<S>; (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknown, th…;
reduce: { (callbackfn: (previousValue: string | number, currentValue: string | number, currentIndex: number, array: ReadonlyArray<string | number>) => string | number): string | number; (callbackfn: (previousValue: string | number, currentValue: s…;
reduceRight: { (callbackfn: (previousValue: string | number, currentValue: string | number, currentIndex: number, array: ReadonlyArray<string | number>) => string | number): string | number; (callbackfn: (previousValue: string | number, currentValue: s…;
find: { (predicate: (value: string | number, index: number, obj: ReadonlyArray<string | number>) => value is S, thisArg?: any): S | undefined; (predicate: (value: string | number, index: number, obj: ReadonlyArray<string | number>) => unknown, t…;
findIndex: (predicate: (value: string | number, index: number, obj: ReadonlyArray<string | number>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, string | number]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<string | number>;
includes: (searchElement: string | number, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: string | number, index: number, array: Array<string | number>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => string | number | undefined;
findLast: { (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => value is S, thisArg?: any): S | undefined; (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknow…;
findLastIndex: (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknown, thisArg?: any) => number;
toReversed: () => Array<string | number>;
toSorted: (compareFn?: ((a: string | number, b: string | number) => number) | undefined) => Array<string | number>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<string | number>): Array<string | number>; (start: number, deleteCount?: number): Array<string | number> };
with: (index: number, value: string | number) => Array<string | number>;
}
path) =>
import EffectEffect.const map: {
<A, B>(f: (a: A) => B): <E, R>(
self: Effect<A, E, R>
) => Effect<B, E, R>
<A, E, R, B>(
self: Effect<A, E, R>,
f: (a: A) => B
): Effect<B, E, R>
}
Transforms the value inside an effect by applying a function to it.
When to use
Use to transform an effect's success value with a function that returns a
plain value, producing a new effect without changing the original effect's
typed error or context requirements.
Details
map takes a function and applies it to the value contained within an
effect, creating a new effect with the transformed value.
It's important to note that effects are immutable, meaning that the original
effect is not modified. Instead, a new effect is returned with the updated
value.
Example (Choosing map syntax variants)
import { Effect, pipe } from "effect"
const myEffect = Effect.succeed(1)
const transformation = (n: number) => n + 1
const mappedWithPipe = pipe(myEffect, Effect.map(transformation))
const mappedWithDataFirst = Effect.map(myEffect, transformation)
const mappedWithMethod = myEffect.pipe(Effect.map(transformation))
Example (Adding a service charge)
import { Effect, pipe } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
Effect.map(addServiceCharge)
)
Effect.runPromise(finalAmount).then(console.log)
// Output: 101
map(import SubscriptionRefSubscriptionRef.const get: <A>(
self: SubscriptionRef<A>
) => Effect.Effect<A>
Retrieves the current value of the SubscriptionRef.
Example (Reading the current value)
import { Effect, SubscriptionRef } from "effect"
const program = Effect.gen(function*() {
const ref = yield* SubscriptionRef.make(42)
const value = yield* SubscriptionRef.get(ref)
console.log(value)
})
get(const overrides: SubscriptionRef.SubscriptionRef<
Map<string, string>
>
const overrides: {
value: A;
semaphore: Semaphore.Semaphore;
pubsub: PubSub.PubSub<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
overrides), (map: Map<string, string>map) => {
const const value: string | undefinedvalue = map: Map<string, string>map.Map<string, string>.get(key: string): string | undefinedReturns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
get(path: ConfigProvider.Path(parameter) path: {
length: number;
toString: () => string;
toLocaleString: { (): string; (locales: string | string[], options?: Intl.NumberFormatOptions & Intl.DateTimeFormatOptions): string };
concat: { (...items: Array<ConcatArray<string | number>>): Array<string | number>; (...items: Array<string | number | ConcatArray<string | number>>): Array<string | number> };
join: (separator?: string) => string;
slice: (start?: number, end?: number) => Array<string | number>;
indexOf: (searchElement: string | number, fromIndex?: number) => number;
lastIndexOf: (searchElement: string | number, fromIndex?: number) => number;
every: { (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => value is S, thisArg?: any): this is readonly S[]; (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) =>…;
some: (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknown, thisArg?: any) => boolean;
forEach: (callbackfn: (value: string | number, index: number, array: ReadonlyArray<string | number>) => void, thisArg?: any) => void;
map: (callbackfn: (value: string | number, index: number, array: ReadonlyArray<string | number>) => U, thisArg?: any) => Array<U>;
filter: { (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => value is S, thisArg?: any): Array<S>; (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknown, th…;
reduce: { (callbackfn: (previousValue: string | number, currentValue: string | number, currentIndex: number, array: ReadonlyArray<string | number>) => string | number): string | number; (callbackfn: (previousValue: string | number, currentValue: s…;
reduceRight: { (callbackfn: (previousValue: string | number, currentValue: string | number, currentIndex: number, array: ReadonlyArray<string | number>) => string | number): string | number; (callbackfn: (previousValue: string | number, currentValue: s…;
find: { (predicate: (value: string | number, index: number, obj: ReadonlyArray<string | number>) => value is S, thisArg?: any): S | undefined; (predicate: (value: string | number, index: number, obj: ReadonlyArray<string | number>) => unknown, t…;
findIndex: (predicate: (value: string | number, index: number, obj: ReadonlyArray<string | number>) => unknown, thisArg?: any) => number;
entries: () => ArrayIterator<[number, string | number]>;
keys: () => ArrayIterator<number>;
values: () => ArrayIterator<string | number>;
includes: (searchElement: string | number, fromIndex?: number) => boolean;
flatMap: (callback: (this: This, value: string | number, index: number, array: Array<string | number>) => U | ReadonlyArray<U>, thisArg?: This | undefined) => Array<U>;
flat: (this: A, depth?: D | undefined) => Array<FlatArray<A, D>>;
at: (index: number) => string | number | undefined;
findLast: { (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => value is S, thisArg?: any): S | undefined; (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknow…;
findLastIndex: (predicate: (value: string | number, index: number, array: ReadonlyArray<string | number>) => unknown, thisArg?: any) => number;
toReversed: () => Array<string | number>;
toSorted: (compareFn?: ((a: string | number, b: string | number) => number) | undefined) => Array<string | number>;
toSpliced: { (start: number, deleteCount: number, ...items: Array<string | number>): Array<string | number>; (start: number, deleteCount?: number): Array<string | number> };
with: (index: number, value: string | number) => Array<string | number>;
}
path.ReadonlyArray<string | number>.join(separator?: string): stringAdds all the elements of an array separated by the specified separator string.
join("_"));
return const value: string | undefinedvalue === var undefinedundefined
? var undefinedundefined
: import ConfigProviderConfigProvider.function makeValue(value: string): NodeCreates a Value node representing a terminal string leaf.
When to use
Use when building nodes inside a custom ConfigProvider's get
callback.
Details
The function returns a new plain object.
Example (Creating a value node)
import { ConfigProvider } from "effect"
const node = ConfigProvider.makeValue("3000")
// { _tag: "Value", value: "3000" }
makeValue(const value: stringvalue);
}),
);
// allowlist = the process-wide registry, plus this config's own swappable keys.
const const allowed: Map<
string,
Config.Config<unknown>
>
allowed = new var Map: MapConstructor
new <string, Config.Config<unknown>>(iterable?: Iterable<readonly [string, Config.Config<unknown>]> | null | undefined) => Map<string, Config.Config<unknown>> (+3 overloads)
Map<string, import ConfigConfig.interface Config<out T>A recipe for extracting a typed value T from a ConfigProvider.
When to use
Use to describe typed configuration that can be parsed from a provider or
yielded inside Effect.gen.
Details
Key members:
parse(provider, pathPrefix?) – runs the config against a specific provider.
The optional path prefix is the logical scope accumulated from outer
Config.nested calls.
- Yieldable – can be yielded inside
Effect.gen, which automatically
resolves the current ConfigProvider from the context.
- Pipeable – supports
.pipe(Config.map(...)) etc.
Config<unknown>>(
yield* const SwappableRegistry: Context.Reference<
Map<string, Config.Config<unknown>>
>
const SwappableRegistry: {
key: string;
Service: {
clear: () => void;
delete: (key: string) => boolean;
forEach: (callbackfn: (value: Config.Config<unknown>, key: string, map: Map<string, Config.Config<unknown>>) => void, thisArg?: any) => void;
get: (key: string) => Config.Config<unknown> | undefined;
has: (key: string) => boolean;
set: (key: string, value: Config.Config<unknown>) => Map<string, Config.Config<unknown>>;
size: number;
entries: () => MapIterator<[string, Config.Config<unknown>]>;
keys: () => MapIterator<string>;
values: () => MapIterator<Config.Config<unknown>>;
};
defaultValue: () => Shape;
of: (this: void, self: Map<string, Config.Config<unknown>>) => Map<string, Config.Config<unknown>>;
context: (self: Map<string, Config.Config<unknown>>) => Context.Context<never>;
use: (f: (service: Map<string, Config.Config<unknown>>) => Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
useSync: (f: (service: Map<string, Config.Config<unknown>>) => A) => Effect.Effect<A, never, never>;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
The process-wide allowlist of declared-swappable env keys → their Config, held the way
Effect holds its own registries (Metric.MetricRegistry): a Context.Reference whose
cached default is the global — declare
swappable
anywhere, no wiring — while a
test or isolated program can substitute its own allowlist with
Effect.provideService(SwappableRegistry, new Map()).
SwappableRegistry,
);
if (config: FieldRecord | ConfigField<unknown>config !== var undefinedundefined) {
for (const const field: ConfigField<unknown>const field: {
config: Config.Config<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
field of const fieldsOf: (
config: FieldRecord | ConfigField<unknown>
) => ReadonlyArray<ConfigField<unknown>>
fieldsOf(config: FieldRecord | ConfigField<unknown>config)) {
if (const isSwappableField: (
field: ConfigField<unknown>
) => field is SwappableField<unknown>
True for a field carrying the swap controls (structural — has .set).
isSwappableField(const field: ConfigField<unknown>const field: {
config: Config.Config<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
field)) {
for (const const key: stringkey of const metaOf: (
field: ConfigField<unknown>
) => ConfigFieldMeta
metaOf(const field: SwappableField<unknown>const field: {
set: (value: string) => Effect.Effect<void, Config.ConfigError, DynamicConfigStore>;
reset: Effect.Effect<void, never, DynamicConfigStore>;
changes: Stream.Stream<ReadonlyArray<string>, never, DynamicConfigStore>;
config: Config.Config<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
field).ConfigFieldMeta.envKeys: readonly string[]envKeys) {
const allowed: Map<
string,
Config.Config<unknown>
>
allowed.Map<string, Config<unknown>>.set(key: string, value: Config.Config<unknown>): Map<string, Config.Config<unknown>>Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
set(const key: stringkey, const field: SwappableField<unknown>const field: {
set: (value: string) => Effect.Effect<void, Config.ConfigError, DynamicConfigStore>;
reset: Effect.Effect<void, never, DynamicConfigStore>;
changes: Stream.Stream<ReadonlyArray<string>, never, DynamicConfigStore>;
config: Config.Config<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
field.ConfigField<unknown>.config: Config.Config<A>(property) ConfigField<unknown>.config: {
parse: (provider: ConfigProvider.ConfigProvider, pathPrefix?: Path) => Effect.Effect<T, ConfigError>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
config);
}
}
}
}
const const store: {
readonly setRaw: (
entries: ReadonlyArray<
readonly [string, string]
>
) => Effect.Effect<void>
readonly unsetRaw: (
keys: ReadonlyArray<string>
) => Effect.Effect<void>
readonly changedKeys: Stream.Stream<
ReadonlyArray<string>
>
readonly allowed: ReadonlyMap<
string,
Config.Config<unknown>
>
}
store = class DynamicConfigStoreclass DynamicConfigStore {
key: Identifier;
Service: {
setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>;
unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>;
changedKeys: Stream.Stream<ReadonlyArray<string>>;
allowed: ReadonlyMap<string, Config.Config<unknown>>;
};
of: (this: void, self: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<st…;
context: (self: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>>; read…;
use: (f: (service: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>…;
useSync: (f: (service: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Shared override store. Provided by
layer
; written by a swappable
field's .set / .reset (and
setByKey
), and read (as a
ConfigProvider) by every Config.
DynamicConfigStore.function Service(this: void, self: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>>; readonly allowed: ReadonlyMap<string, Config.Config<unknown>> }): { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>>; readonly allowed: ReadonlyMap<string, Config.Config<unknown>> }of({
setRaw: (
entries: ReadonlyArray<
readonly [string, string]
>
) => Effect.Effect<void>
setRaw: (entries: readonly (readonly [string, string])[]entries) =>
import SubscriptionRefSubscriptionRef.const update: {
<A>(update: (a: A) => A): (
self: SubscriptionRef<A>
) => Effect.Effect<void>
<A>(
self: SubscriptionRef<A>,
update: (a: A) => A
): Effect.Effect<void>
}
Updates the value of the SubscriptionRef with the result of applying a
function, notifying subscribers of the change.
Example (Updating a value)
import { Effect, SubscriptionRef } from "effect"
const program = Effect.gen(function*() {
const ref = yield* SubscriptionRef.make(10)
yield* SubscriptionRef.update(ref, (n) => n * 2)
const value = yield* SubscriptionRef.get(ref)
console.log(value)
})
update(const overrides: SubscriptionRef.SubscriptionRef<
Map<string, string>
>
const overrides: {
value: A;
semaphore: Semaphore.Semaphore;
pubsub: PubSub.PubSub<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
overrides, (map: Map<string, string>map) => {
const const next: Map<string, string>next = new var Map: MapConstructor
new <string, string>(iterable?: Iterable<readonly [string, string]> | null | undefined) => Map<string, string> (+3 overloads)
Map(map: Map<string, string>map);
for (const [const key: stringkey, const value: stringvalue] of entries: readonly (readonly [string, string])[]entries) {
const next: Map<string, string>next.Map<string, string>.set(key: string, value: string): Map<string, string>Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
set(const key: stringkey, const value: stringvalue);
}
return const next: Map<string, string>next;
}),
unsetRaw: (
keys: ReadonlyArray<string>
) => Effect.Effect<void>
unsetRaw: (keys: readonly string[]keys) =>
import SubscriptionRefSubscriptionRef.const update: {
<A>(update: (a: A) => A): (
self: SubscriptionRef<A>
) => Effect.Effect<void>
<A>(
self: SubscriptionRef<A>,
update: (a: A) => A
): Effect.Effect<void>
}
Updates the value of the SubscriptionRef with the result of applying a
function, notifying subscribers of the change.
Example (Updating a value)
import { Effect, SubscriptionRef } from "effect"
const program = Effect.gen(function*() {
const ref = yield* SubscriptionRef.make(10)
yield* SubscriptionRef.update(ref, (n) => n * 2)
const value = yield* SubscriptionRef.get(ref)
console.log(value)
})
update(const overrides: SubscriptionRef.SubscriptionRef<
Map<string, string>
>
const overrides: {
value: A;
semaphore: Semaphore.Semaphore;
pubsub: PubSub.PubSub<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
overrides, (map: Map<string, string>map) => {
const const next: Map<string, string>next = new var Map: MapConstructor
new <string, string>(iterable?: Iterable<readonly [string, string]> | null | undefined) => Map<string, string> (+3 overloads)
Map(map: Map<string, string>map);
for (const const key: stringkey of keys: readonly string[]keys) {
const next: Map<string, string>next.Map<string, string>.delete(key: string): booleandelete(const key: stringkey);
}
return const next: Map<string, string>next;
}),
changedKeys: Stream.Stream<
Array<string>,
never,
never
>
(property) changedKeys: {
channel: Channel.Channel<Arr.NonEmptyReadonlyArray<A>, E, void, unknown, unknown, unknown, R>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
changedKeys: import StreamStream.const map: {
<A, B>(f: (a: A, i: number) => B): <E, R>(
self: Stream<A, E, R>
) => Stream<B, E, R>
<A, E, R, B>(
self: Stream<A, E, R>,
f: (a: A, i: number) => B
): Stream<B, E, R>
}
Transforms the elements of this stream using the supplied function.
Example (Mapping stream values)
import { Console, Effect, Stream } from "effect"
const stream = Stream.fromArray([1, 2, 3]).pipe(Stream.map((n, i) => n + i))
const program = Stream.runCollect(stream).pipe(
Effect.tap((values) => Console.log(values))
)
Effect.runPromise(program)
// [ 1, 3, 5 ]
map(import SubscriptionRefSubscriptionRef.const changes: <A>(
self: SubscriptionRef<A>
) => Stream.Stream<A>
Creates a stream that emits the current value and all subsequent changes to
the SubscriptionRef.
Details
The stream will first emit the current value, then emit all future changes
as they occur.
Example (Streaming changes)
import { Deferred, Effect, Fiber, Stream, SubscriptionRef } from "effect"
const program = Effect.gen(function*() {
const ref = yield* SubscriptionRef.make(0)
const ready = yield* Deferred.make<void>()
const fiber = yield* SubscriptionRef.changes(ref).pipe(
Stream.tap(() => Deferred.succeed(ready, void 0)),
Stream.take(3),
Stream.runCollect,
Effect.forkChild
)
yield* Deferred.await(ready)
yield* SubscriptionRef.set(ref, 1)
yield* SubscriptionRef.set(ref, 2)
const values = yield* Fiber.join(fiber)
console.log(values) // [ 0, 1, 2 ]
})
Effect.runPromise(program)
changes(const overrides: SubscriptionRef.SubscriptionRef<
Map<string, string>
>
const overrides: {
value: A;
semaphore: Semaphore.Semaphore;
pubsub: PubSub.PubSub<A>;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
overrides), (map: Map<string, string>map) =>
var Array: ArrayConstructorArray.ArrayConstructor.from<string>(iterable: Iterable<string> | ArrayLike<string>): string[] (+3 overloads)Creates an array from an iterable object.
from(map: Map<string, string>map.Map<string, string>.keys(): MapIterator<string>Returns an iterable of keys in the map
keys()),
),
allowed: Map<string, Config.Config<unknown>>This provision's
setByKey
allowlist: the process-wide
SwappableRegistry
(from
globalSwappable
) plus any
swappable
fields in the config passed to
layer
.
allowed,
});
return import LayerLayer.const merge: {
<RIn, E, ROut>(that: Layer<ROut, E, RIn>): <
RIn2,
E2,
ROut2
>(
self: Layer<ROut2, E2, RIn2>
) => Layer<ROut | ROut2, E | E2, RIn | RIn2>
<Layers extends [Any, ...Array<Any>]>(
that: Layers
): <A, E, R>(
self: Layer<A, E, R>
) => Layer<
A | Success<Layers[number]>,
E | Error<Layers[number]>,
Services<Layers[number]> | R
>
<RIn2, E2, ROut2, RIn, E, ROut>(
self: Layer<ROut2, E2, RIn2>,
that: Layer<ROut, E, RIn>
): Layer<ROut | ROut2, E | E2, RIn | RIn2>
<A, E, R, Layers extends [Any, ...Array<Any>]>(
self: Layer<A, E, R>,
that: Layers
): Layer<
A | Success<Layers[number]>,
E | Error<Layers[number]>,
Services<Layers[number]> | R
>
}
Merges this layer with another layer concurrently, producing a new layer with
combined input, error, and output types.
When to use
Use to combine an existing Layer with another Layer or an array of
layers while preserving pipeline style.
Details
This is a binary version of mergeAll that merges exactly two layers or one
layer with an array of layers. The layers are built concurrently and their
outputs are combined.
Example (Merging two layers)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
const dbLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed("result"))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(msg)))
})
const mergedLayer = Layer.merge(dbLayer, loggerLayer)
merge(
import ConfigProviderConfigProvider.const layer: <E = never, R = never>(
self:
| ConfigProvider
| Effect.Effect<ConfigProvider, E, R>
) => Layer.Layer<never, E, Exclude<R, Scope>>
Provides a layer that installs a ConfigProvider as the active provider for
all downstream effects, replacing any previously installed provider.
When to use
Use to set the config source for an entire application or test suite.
Details
Accepts either a plain ConfigProvider or an Effect that produces one.
When given an Effect, it is evaluated once when the layer is built.
Example (Reading config from a JSON object)
import { Config, ConfigProvider, Effect, Layer } from "effect"
const TestLayer = ConfigProvider.layer(
ConfigProvider.fromUnknown({ port: 8080 })
)
const program = Effect.gen(function*() {
const port = yield* Config.number("port")
return port
})
// Effect.runSync(Effect.provide(program, TestLayer)) // 8080
layer(
import ConfigProviderConfigProvider.const orElse: {
(that: ConfigProvider): (
self: ConfigProvider
) => ConfigProvider
(
self: ConfigProvider,
that: ConfigProvider
): ConfigProvider
}
Returns a provider that falls back to that when self returns undefined
for a path.
When to use
Use to layer multiple config sources, such as env vars plus a defaults file,
or provide partial overrides on top of a base config.
Details
Each provider keeps its own path transformations. If the combined provider
is later transformed with
mapInput
or
nested
, the
transformation is applied to both sides.
Gotchas
The fallback only runs when the path is not found (undefined). A
SourceError from self is not caught; it propagates immediately.
Example (Falling back to a default provider)
import { ConfigProvider } from "effect"
const envProvider = ConfigProvider.fromEnv({
env: { HOST: "prod.example.com" }
})
const defaults = ConfigProvider.fromUnknown({ HOST: "localhost", PORT: "3000" })
const combined = ConfigProvider.orElse(envProvider, defaults)
orElse(const provider: ConfigProvider.ConfigProviderconst provider: {
load: (path: Path) => Effect.Effect<Node | undefined, SourceError>;
state: ProviderState;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
}
provider, import ConfigProviderConfigProvider.function fromEnv(options?: {
readonly env?:
| Record<string, string>
| undefined
readonly preserveEmptyStrings?:
| boolean
| undefined
}): ConfigProvider
Creates a ConfigProvider backed by environment variables.
When to use
Use to read configuration from process.env, which is the default when no
provider is explicitly set, or pass a custom env record for testing or
non-Node runtimes.
Details
Path segments are joined with _ for direct lookup, and env var names are
also split on _ to build a trie for child key discovery. This means
DATABASE_HOST=localhost is accessible at both path ["DATABASE_HOST"]
and ["DATABASE", "HOST"]. If all immediate children of a trie node have
purely numeric names, the node is reported as an Array; otherwise as a
Record.
The default environment merges process.env and import.meta.env (when
available). Override by passing { env: { ... } }.
Literal empty strings are treated as missing values when loaded as values by
default. Pass { preserveEmptyStrings: true } to keep empty strings as
explicit values. Child discovery still reflects the environment variable
names present in the source.
Never fails with SourceError — all lookups are synchronous.
Example (Reading from a custom env record)
import { Config, ConfigProvider, Effect } from "effect"
const provider = ConfigProvider.fromEnv({
env: {
DATABASE_HOST: "localhost",
DATABASE_PORT: "5432"
}
})
const host = Config.string("HOST").parse(
provider.pipe(ConfigProvider.nested("DATABASE"))
)
// Effect.runSync(host) // "localhost"
fromEnv()),
),
import LayerLayer.const succeed: {
<I, S>(service: Context.Key<I, S>): (
resource: S
) => Layer<I>
<I, S>(
service: Context.Key<I, S>,
resource: Types.NoInfer<S>
): Layer<I>
}
Constructs a layer that provides a single service from an already available
value.
When to use
Use when you need a Layer that provides a service from an already
constructed implementation without effectful acquisition.
Example (Creating a layer from a service implementation)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
const DatabaseLive = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`Query result: ${sql}`))
})
succeed(class DynamicConfigStoreclass DynamicConfigStore {
key: Identifier;
Service: {
setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>;
unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>;
changedKeys: Stream.Stream<ReadonlyArray<string>>;
allowed: ReadonlyMap<string, Config.Config<unknown>>;
};
of: (this: void, self: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<st…;
context: (self: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>>; read…;
use: (f: (service: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>…;
useSync: (f: (service: { readonly setRaw: (entries: ReadonlyArray<readonly [string, string]>) => Effect.Effect<void>; readonly unsetRaw: (keys: ReadonlyArray<string>) => Effect.Effect<void>; readonly changedKeys: Stream.Stream<ReadonlyArray<string>…;
Identifier: Identifier;
stack: string | undefined;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
Shared override store. Provided by
layer
; written by a swappable
field's .set / .reset (and
setByKey
), and read (as a
ConfigProvider) by every Config.
DynamicConfigStore, const store: {
readonly setRaw: (
entries: ReadonlyArray<
readonly [string, string]
>
) => Effect.Effect<void>
readonly unsetRaw: (
keys: ReadonlyArray<string>
) => Effect.Effect<void>
readonly changedKeys: Stream.Stream<
ReadonlyArray<string>
>
readonly allowed: ReadonlyMap<
string,
Config.Config<unknown>
>
}
store),
);
}),
);