(
node: AnyNode & { readonly key: string },
serves: ReadonlyArray<string>,
options?: { readonly onConflict?: OnConflict }
): Layer.Layer<never, IncumbentAlive>Soft directory advertise for Node.unix / Node.http / Node.ws: when
Directory is in the environment, register node with the given serves keys and
unregister on scope close. No-op when Directory is absent (local-only listen).
serves is derived from the protocol-listen serve list (group ids) after registration.
Duplicate nodeKey with a live incumbent fails the layer with IncumbentAlive.
options.onConflict is the call-site preference; combined with the node's stamp before
the wire request (may still be "inherit" for the Lookup server to finish).
export const const directoryAdvertiseLayer: (
node: AnyNode & { readonly key: string },
serves: ReadonlyArray<string>,
options?: { readonly onConflict?: OnConflict }
) => Layer.Layer<never, IncumbentAlive>
Soft directory advertise for
Node.unix
/
Node.http
/
Node.ws
: when
Directory
is in the environment, register node with the given serves keys and
unregister
on scope close. No-op when Directory is absent (local-only listen).
serves is derived from the protocol-listen serve list (group ids) after registration.
Duplicate nodeKey with a live incumbent fails the layer with
IncumbentAlive
.
options.onConflict is the call-site preference; combined with the node's stamp before
the wire request (may still be "inherit" for the Lookup server to finish).
directoryAdvertiseLayer = (
node: anynode: import AnyNodeAnyNode & { readonly key: stringkey: string },
serves: readonly string[]serves: interface ReadonlyArray<T>ReadonlyArray<string>,
options: | {
readonly onConflict?: OnConflict
}
| undefined
options?: { readonly onConflict?: anyonConflict?: import OnConflictOnConflict },
): 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<never, class IncumbentAliveclass IncumbentAlive {
_tag: 'IncumbentAlive';
nodeKey: string;
incumbent: DirectoryEntry;
name: string;
message: string;
stack: string;
cause: unknown;
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;
}
Advertise rejected — an incumbent with the same nodeKey still answers NodeStatus ping.
IncumbentAlive> =>
import LayerLayer.const effectDiscard: <void, unknown, unknown>(effect: Effect.Effect<void, unknown, unknown>) => Layer.Layer<never, unknown, unknown>Constructs a layer from an effect, discarding its value and providing no
services.
When to use
Use when layer construction should run an Effect for its side effects while providing no
services.
Example (Running an effect during layer construction)
import { Effect, Layer } from "effect"
const initLayer = Layer.effectDiscard(
Effect.sync(() => {
console.log("Initializing application...")
})
)
effectDiscard(
import EffectEffect.const gen: <any, void>(f: () => Generator<any, void, never>) => Effect.Effect<void, unknown, unknown> (+1 overload)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 dirOpt: Option.Option<unknown>dirOpt = yield* import EffectEffect.const serviceOption: <unknown, unknown>(
key: Key<unknown, unknown>
) => Effect.Effect<
Option.Option<unknown>,
never,
never
>
Optionally accesses a service from the environment.
When to use
Use to read an optional dependency from the current context without making
that dependency part of the effect's required environment.
Details
This function attempts to access a service from the environment. If the
service is available, it returns Some(service). If the service is not
available, it returns None. Unlike service, this function does not
require the service to be present in the environment.
Example (Accessing an optional service)
import { Context, Effect, Option } from "effect"
// Define a service key
const Logger = Context.Service<{
log: (msg: string) => void
}>("Logger")
// Use serviceOption to optionally access the logger
const program = Effect.gen(function*() {
const maybeLogger = yield* Effect.serviceOption(Logger)
if (Option.isSome(maybeLogger)) {
maybeLogger.value.log("Service is available")
} else {
console.log("Service not available")
}
})
serviceOption(class DirectoryLookup node directory — advertise / unregister / list by served resource key.
Directory);
if (import OptionOption.const isNone: <unknown>(
self: Option.Option<unknown>
) => self is Option.None<unknown>
Checks whether an Option is None (absent).
When to use
Use when you need to branch on an absent Option before accessing .value.
Details
- Acts as a type guard, narrowing to
None<A>
Example (Checking for None)
import { Option } from "effect"
console.log(Option.isNone(Option.some(1)))
// Output: false
console.log(Option.isNone(Option.none()))
// Output: true
isNone(const dirOpt: Option.Option<unknown>dirOpt)) {
return;
}
const const kind: anykind = node: anynode.kind;
if (const kind: anykind === var undefinedundefined) {
return;
}
// Advertiser side: call-site → node stamp; leave `"inherit"` so Lookup finishes.
const const callSite: anycallSite = options: | {
readonly onConflict?: OnConflict
}
| undefined
options?.onConflict?: anyonConflict;
const const nodeStamp: anynodeStamp = import onConflictOfonConflictOf(node: anynode);
const const wireOnConflict: OnConflictwireOnConflict: import OnConflictOnConflict =
const callSite: anycallSite !== var undefinedundefined && const callSite: anycallSite !== "inherit"
? const callSite: anycallSite
: const nodeStamp: anynodeStamp !== var undefinedundefined && const nodeStamp: anynodeStamp !== "inherit"
? const nodeStamp: anynodeStamp
: "inherit";
yield* const dirOpt: Option.Some<unknown>const dirOpt: {
_tag: "Some";
_op: "Some";
value: A;
valueOrUndefined: 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;
}
dirOpt.Some<unknown>.value: unknownvalue.advertise(
new constructor AdvertiseRequest(props: {
readonly kind: "Http" | "WebSocket" | "IpcSocket";
readonly serves: readonly string[];
readonly nodeKey: string;
readonly url?: string | undefined;
readonly path?: string | undefined;
readonly onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined;
}, options?: Schema.MakeOptions | undefined): AdvertiseRequest
constructor AdvertiseRequest(props: {
readonly kind: "Http" | "WebSocket" | "IpcSocket";
readonly serves: readonly string[];
readonly nodeKey: string;
readonly url?: string | undefined;
readonly path?: string | undefined;
readonly onConflict?: "livenessReplace" | "askIncumbent" | "reject" | "inherit" | undefined;
}, options?: Schema.MakeOptions | undefined): {
Type: Self;
Encoded: S["Encoded"];
DecodingServices: S["DecodingServices"];
EncodingServices: S["EncodingServices"];
Iso: S["Iso"];
identifier: string;
fields: S["fields"];
mapFields: (f: (fields: { readonly nodeKey: Schema.String; readonly kind: Schema.Literals<readonly ['Http', 'WebSocket', 'IpcSocket']>; readonly url: Schema.optionalKey<Schema.String>; readonly path: Schema.optionalKey<Schema.String>; readonly serves…;
extend: (identifier: string) => { (fields: NewFields, annotations?: Schema.Annotations.Declaration<Extended, readonly [Schema.Struct<{ [K in keyof { [K in keyof (('kind' | 'url' | 'path' | 'serves' | 'nodeKey' | 'onConflict') & keyof NewFields ext…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<AdvertiseRequest, readonly [Schema.Struct<{ readonly nodeKey: Schema.String; readonly kind: Schema.Literals<readonly ['Http', 'WebSocket', 'IpcSocket']>; readonly url: Schema.optionalKey<Schema.Strin…;
annotateKey: (annotations: Schema.Annotations.Key<AdvertiseRequest>) => Schema.decodeTo<Schema.declareConstructor<AdvertiseRequest, { readonly kind: 'Http' | 'WebSocket' | 'IpcSocket'; readonly serves: ReadonlyArray<string>; readonly nodeKey: string; r…;
check: (checks_0: Check<AdvertiseRequest>, ...checks: Array<Check<AdvertiseRequest>>) => Schema.decodeTo<Schema.declareConstructor<AdvertiseRequest, { readonly kind: 'Http' | 'WebSocket' | 'IpcSocket'; readonly serves: ReadonlyArray<string>; read…;
rebuild: (ast: Declaration) => Schema.decodeTo<Schema.declareConstructor<AdvertiseRequest, { readonly kind: 'Http' | 'WebSocket' | 'IpcSocket'; readonly serves: ReadonlyArray<string>; readonly nodeKey: string; readonly url?: string | undefined; rea…;
make: (input: { readonly kind: 'Http' | 'WebSocket' | 'IpcSocket'; readonly serves: ReadonlyArray<string>; readonly nodeKey: string; readonly url?: string | undefined; readonly path?: string | undefined; readonly onConflict?: 'livenessReplace' |…;
makeOption: (input: { readonly kind: 'Http' | 'WebSocket' | 'IpcSocket'; readonly serves: ReadonlyArray<string>; readonly nodeKey: string; readonly url?: string | undefined; readonly path?: string | undefined; readonly onConflict?: 'livenessReplace' |…;
makeEffect: (input: { readonly kind: 'Http' | 'WebSocket' | 'IpcSocket'; readonly serves: ReadonlyArray<string>; readonly nodeKey: string; readonly url?: string | undefined; readonly path?: string | undefined; readonly onConflict?: 'livenessReplace' |…;
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; <…;
}
Advertise / refresh a directory row.
AdvertiseRequest({
nodeKey: stringnodeKey: node: anynode.key,
kind: "Http" | "WebSocket" | "IpcSocket"kind,
serves: readonly string[]serves: [...serves: readonly string[]serves],
onConflict?: | "livenessReplace"
| "askIncumbent"
| "reject"
| "inherit"
| undefined
Advertiser preference after call-site∋node resolve — may still be "inherit".
Lookup finishes resolve with its node stamp. Omit → inherit.
onConflict: const wireOnConflict: OnConflictwireOnConflict,
...(typeof node: anynode.path === "string" ? { path?: string | undefinedpath: node: anynode.path } : {}),
...(typeof node: anynode.url === "string" ? { url?: string | undefinedurl: node: anynode.url } : {}),
}),
);
yield* import EffectEffect.const addFinalizer: <unknown>(
finalizer: (
exit: Exit.Exit<unknown, unknown>
) => Effect.Effect<void, never, unknown>
) => Effect.Effect<void, never, unknown>
Adds a finalizer to the current scope.
When to use
Use to register low-level cleanup in the current scope.
Details
The finalizer runs when the surrounding scope is closed and receives the
Exit value used to close the scope.
Example (Registering scope finalizers)
import { Console, Effect, Exit } from "effect"
const program = Effect.scoped(
Effect.gen(function*() {
// Add a finalizer that runs when the scope closes
yield* Effect.addFinalizer((exit) =>
Console.log(
Exit.isSuccess(exit)
? "Cleanup: Operation completed successfully"
: "Cleanup: Operation failed, cleaning up resources"
)
)
yield* Console.log("Performing main operation...")
// This could succeed or fail
return "operation result"
})
)
Effect.runPromise(program).then(console.log)
// Output:
// Performing main operation...
// Cleanup: Operation completed successfully
// operation result
addFinalizer(() =>
const dirOpt: Option.Some<unknown>const dirOpt: {
_tag: "Some";
_op: "Some";
value: A;
valueOrUndefined: 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;
}
dirOpt.Some<unknown>.value: unknownvalue
.unregister(
new constructor UnregisterRequest(props: {
readonly nodeKey: string;
readonly kind?: "Http" | "WebSocket" | "IpcSocket" | undefined;
readonly url?: string | undefined;
readonly path?: string | undefined;
}, options?: Schema.MakeOptions | undefined): UnregisterRequest
constructor UnregisterRequest(props: {
readonly nodeKey: string;
readonly kind?: "Http" | "WebSocket" | "IpcSocket" | undefined;
readonly url?: string | undefined;
readonly path?: string | undefined;
}, options?: Schema.MakeOptions | undefined): {
Type: Self;
Encoded: S["Encoded"];
DecodingServices: S["DecodingServices"];
EncodingServices: S["EncodingServices"];
Iso: S["Iso"];
identifier: string;
fields: S["fields"];
mapFields: (f: (fields: { readonly nodeKey: Schema.String; readonly kind: Schema.optionalKey<Schema.Literals<readonly ['Http', 'WebSocket', 'IpcSocket']>>; readonly url: Schema.optionalKey<Schema.String>; readonly path: Schema.optionalKey<Schema.Stri…;
extend: (identifier: string) => { (fields: NewFields, annotations?: Schema.Annotations.Declaration<Extended, readonly [Schema.Struct<{ [K in keyof { [K in keyof (('kind' | 'url' | 'path' | 'nodeKey') & keyof NewFields extends never ? { readonly no…;
Rebuild: Rebuild;
ast: Ast;
annotate: (annotations: Schema.Annotations.Bottom<UnregisterRequest, readonly [Schema.Struct<{ readonly nodeKey: Schema.String; readonly kind: Schema.optionalKey<Schema.Literals<readonly ['Http', 'WebSocket', 'IpcSocket']>>; readonly url: Schema.opt…;
annotateKey: (annotations: Schema.Annotations.Key<UnregisterRequest>) => Schema.decodeTo<Schema.declareConstructor<UnregisterRequest, { readonly nodeKey: string; readonly kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; readonly url?: string | un…;
check: (checks_0: Check<UnregisterRequest>, ...checks: Array<Check<UnregisterRequest>>) => Schema.decodeTo<Schema.declareConstructor<UnregisterRequest, { readonly nodeKey: string; readonly kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; re…;
rebuild: (ast: Declaration) => Schema.decodeTo<Schema.declareConstructor<UnregisterRequest, { readonly nodeKey: string; readonly kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; readonly url?: string | undefined; readonly path?: string | unde…;
make: (input: { readonly nodeKey: string; readonly kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; readonly url?: string | undefined; readonly path?: string | undefined }, options?: Schema.MakeOptions) => UnregisterRequest;
makeOption: (input: { readonly nodeKey: string; readonly kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; readonly url?: string | undefined; readonly path?: string | undefined }, options?: Schema.MakeOptions) => Option.Option<UnregisterRequest>;
makeEffect: (input: { readonly nodeKey: string; readonly kind?: 'Http' | 'WebSocket' | 'IpcSocket' | undefined; readonly url?: string | undefined; readonly path?: string | undefined }, options?: Schema.MakeOptions) => Effect.Effect<UnregisterRequest, …;
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; <…;
}
Unregister payload — remove a directory row by nodeKey.
When dial fields are present, remove only if the stored dial still matches
(askIncumbent-safe finalizers).
UnregisterRequest({
nodeKey: stringnodeKey: node: anynode.key,
kind?: | "Http"
| "WebSocket"
| "IpcSocket"
| undefined
kind,
...(typeof node: anynode.path === "string" ? { path?: string | undefinedpath: node: anynode.path } : {}),
...(typeof node: anynode.url === "string" ? { url?: string | undefinedurl: node: anynode.url } : {}),
}),
)
.pipe(import EffectEffect.const ignore: <
Arg extends
| Effect.Effect<any, any, any>
| {
readonly log?:
| boolean
| Severity
| undefined
readonly message?: string | undefined
}
| undefined = {
readonly log?: boolean | Severity | undefined
readonly message?: string | undefined
}
>(
effectOrOptions?: Arg,
options?:
| {
readonly log?:
| boolean
| Severity
| undefined
readonly message?: string | undefined
}
| undefined
) => [Arg] extends [
Effect.Effect<infer _A, infer _E, infer _R>
]
? Effect.Effect<void, never, _R>
: <A, E, R>(
self: Effect.Effect<A, E, R>
) => Effect.Effect<void, never, R>
Discards both the success and failure values of an effect.
When to use
Use when an effect should run for its side effects while both success and
failure values are discarded.
Details
Use the log option to emit the full
Cause
when the effect fails,
and message to prepend a custom log message.
Example (Discarding success and failure values)
import { Effect } from "effect"
// ┌─── Effect<number, string, never>
// ▼
const task = Effect.fail("Uh oh!").pipe(Effect.as(5))
// ┌─── Effect<void, never, never>
// ▼
const program = task.pipe(Effect.ignore)
Example (Logging failures while ignoring results)
import { Effect } from "effect"
const task = Effect.fail("Uh oh!")
const program = task.pipe(Effect.ignore({ log: true }))
const programWarn = task.pipe(Effect.ignore({ log: "Warn", message: "Ignoring task failure" }))
ignore),
);
}),
);