(spec: SpawnSpec): Effect.Effect<
Handle,
PlatformError,
ChildProcessSpawner.ChildProcessSpawner | Scope.Scope
>Spawn one OS child under launcher custody — mints an assume token, runs process, returns
a Handle. Requires ChildProcessSpawner + Scope (provide @effect/platform-node
layers at the app edge).
export const const spawn: (
spec: SpawnSpec
) => Effect.Effect<
Handle,
PlatformError,
| ChildProcessSpawner.ChildProcessSpawner
| Scope.Scope
>
Spawn one OS child under launcher custody — mints an assume token, runs process, returns
a
Handle
. Requires ChildProcessSpawner + Scope (provide @effect/platform-node
layers at the app edge).
spawn = (
spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec: SpawnSpec,
): import EffectEffect.interface Effect<out A, out E = never, out R = never>The Effect interface defines a value that lazily describes a workflow or
job. The workflow requires some context R, and may fail with an error of
type E, or succeed with a value of type A.
When to use
Use when you need to represent a lazy, composable workflow that can require
services, fail with a typed error, or succeed with a typed value.
Details
Effect values model resourceful interaction with the outside world,
including synchronous, asynchronous, concurrent, and parallel interaction.
They use a fiber-based concurrency model, with built-in support for
scheduling, fine-grained interruption, structured concurrency, and high
scalability.
To run an Effect value, you need a Runtime, which is a type that is
capable of executing Effect values.
Effect<
Handle,
class PlatformErrorclass PlatformError {
message: string;
name: 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;
_tag: Tag;
reason: BadArgument | SystemError;
}
Tagged error used by platform APIs to report either invalid arguments or
system-level failures.
When to use
Use as the shared error type for platform APIs that expose invalid arguments
and host or operating-system failures through a single Effect error
channel.
Details
The reason field contains the underlying BadArgument or SystemError.
When that reason has a cause, the cause is preserved on the wrapper.
PlatformError,
import ChildProcessSpawnerChildProcessSpawner.class ChildProcessSpawnerclass ChildProcessSpawner {
key: Identifier;
Service: {
spawn: (command: Command) => Effect.Effect<ChildProcessHandle, PlatformError.PlatformError, Scope.Scope>;
exitCode: (command: Command) => Effect.Effect<ExitCode, PlatformError.PlatformError>;
streamString: (command: Command, options?: { readonly includeStderr?: boolean | undefined }) => Stream.Stream<string, PlatformError.PlatformError>;
streamLines: (command: Command, options?: { readonly includeStderr?: boolean | undefined }) => Stream.Stream<string, PlatformError.PlatformError>;
lines: (command: Command, options?: { readonly includeStderr?: boolean | undefined }) => Effect.Effect<Array<string>, PlatformError.PlatformError>;
string: (command: Command, options?: { readonly includeStderr?: boolean | undefined }) => Effect.Effect<string, PlatformError.PlatformError>;
};
}
Service tag for child process spawning.
ChildProcessSpawner | import ScopeScope.Scope
> =>
const withLauncherPhase: <A, E, R>(
nodeKey: string,
phase: string,
effect: Effect.Effect<A, E, R>
) => Effect.Effect<A, E, R>
withLauncherPhase(
spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec.SpawnSpec.node: AnyNodenode.Key<unknown, NodeProtocol>.key: stringkey,
"spawn",
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 token: Redacted.Redacted<string>const token: {
label: 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; <…;
}
token = yield* const mintToken: Effect.Effect<
Redacted.Redacted<string>
>
const mintToken: {
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;
}
Mint an opaque high-entropy assume token (CSPRNG hex) and wrap in
Redacted
.
mintToken;
const const clear: stringclear = import RedactedRedacted.const value: <T>(self: Redacted<T>) => TRetrieves the original value from a Redacted instance. Use this function
with caution, as it exposes the sensitive data.
When to use
Use when you need the underlying sensitive value at a trusted boundary.
Example (Retrieving a redacted value)
import { Redacted } from "effect"
import * as assert from "node:assert"
const API_KEY = Redacted.make("1234567890")
assert.equal(Redacted.value(API_KEY), "1234567890")
value(const token: Redacted.Redacted<string>const token: {
label: 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; <…;
}
token);
const const command: ChildProcess.Commandcommand =
typeof spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec.SpawnSpec.process: ChildProcess.Command | ((token: string) => ChildProcess.Command)process === "function" ? spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec.SpawnSpec.process: (token: string) => ChildProcess.Commandprocess(const clear: stringclear) : spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec.SpawnSpec.process: ChildProcess.Commandprocess;
const const child: ChildProcessSpawner.ChildProcessHandleconst child: {
pid: ProcessId;
exitCode: Effect.Effect<ExitCode, PlatformError.PlatformError>;
isRunning: Effect.Effect<boolean, PlatformError.PlatformError>;
kill: (options?: KillOptions | undefined) => Effect.Effect<void, PlatformError.PlatformError>;
stdin: Sink.Sink<void, Uint8Array, never, PlatformError.PlatformError>;
stdout: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
stderr: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
all: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
getInputFd: (fd: number) => Sink.Sink<void, Uint8Array, never, PlatformError.PlatformError>;
getOutputFd: (fd: number) => Stream.Stream<Uint8Array, PlatformError.PlatformError>;
unref: Effect.Effect<Reref, PlatformError.PlatformError>;
}
child = yield* const command: ChildProcess.Commandcommand;
const const phase: Ref.Ref<HandlePhase>const phase: {
ref: MutableRef.MutableRef<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; <…;
}
phase = yield* import RefRef.const make: <A>(
value: A
) => Effect.Effect<Ref<A>>
Creates a new Ref with the specified initial value.
When to use
Use to create a Ref for shared mutable state inside an Effect program.
Example (Creating a ref)
import { Effect, Ref } from "effect"
const program = Effect.gen(function*() {
const ref = yield* Ref.make(42)
const value = yield* Ref.get(ref)
console.log(value) // 42
})
make<type HandlePhase =
| "spawned"
| "ready"
| "handedOff"
HandlePhase>("spawned");
const const gate: Semaphore.Semaphoreconst gate: {
resize: (this: Semaphore, permits: number) => Effect.Effect<void>;
withPermits: (this: Semaphore, permits: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
withPermit: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
withPermitsIfAvailable: (this: Semaphore, permits: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Option.Option<A>, E, R>;
take: (this: Semaphore, permits: number) => Effect.Effect<number>;
release: (this: Semaphore, permits: number) => Effect.Effect<number>;
releaseAll: Effect.Effect<number>;
}
gate = yield* import SemaphoreSemaphore.const make: (
permits: number
) => Effect.Effect<Semaphore>
Creates a Semaphore initialized with the specified total number of permits.
When to use
Use to create a semaphore inside Effect code for bounding concurrency with
automatic or manual permit management.
Example (Creating a semaphore)
import { Effect, Semaphore } from "effect"
const program = Effect.gen(function*() {
const semaphore = yield* Semaphore.make(2)
const task = (id: number) =>
semaphore.withPermits(1)(
Effect.gen(function*() {
yield* Effect.log(`Task ${id} acquired permit`)
yield* Effect.sleep("1 second")
yield* Effect.log(`Task ${id} releasing permit`)
})
)
// Run 4 tasks, but only 2 can run concurrently
yield* Effect.all([task(1), task(2), task(3), task(4)])
})
make(1);
yield* import EffectEffect.const logInfo: (
...message: ReadonlyArray<any>
) => Effect<void>
Logs one or more messages at the INFO level.
Example (Logging information)
import { Effect } from "effect"
const program = Effect.gen(function*() {
yield* Effect.logInfo("Application starting up")
yield* Effect.logInfo("Config loaded:", "production", "Port:", 3000)
// Useful for general information
const version = "1.2.3"
yield* Effect.logInfo("Application version:", version)
})
Effect.runPromise(program)
// Output:
// timestamp=2023-... level=INFO message="Application starting up"
// timestamp=2023-... level=INFO message="Config loaded: production Port: 3000"
// timestamp=2023-... level=INFO message="Application version: 1.2.3"
logInfo("child spawned under launcher custody").Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)pipe(
import EffectEffect.const annotateLogs: (values: Record<string, unknown>) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+3 overloads)annotateLogs({ "launcher.pid": var String: StringConstructor
;(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const child: ChildProcessSpawner.ChildProcessHandleconst child: {
pid: ProcessId;
exitCode: Effect.Effect<ExitCode, PlatformError.PlatformError>;
isRunning: Effect.Effect<boolean, PlatformError.PlatformError>;
kill: (options?: KillOptions | undefined) => Effect.Effect<void, PlatformError.PlatformError>;
stdin: Sink.Sink<void, Uint8Array, never, PlatformError.PlatformError>;
stdout: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
stderr: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
all: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
getInputFd: (fd: number) => Sink.Sink<void, Uint8Array, never, PlatformError.PlatformError>;
getOutputFd: (fd: number) => Stream.Stream<Uint8Array, PlatformError.PlatformError>;
unref: Effect.Effect<Reref, PlatformError.PlatformError>;
}
child.ChildProcessHandle.pid: ChildProcessSpawner.ProcessIdThe child process process identifier.
pid) }),
);
return const makeHandle: (options: {
readonly node: AnyNode
readonly token: Redacted.Redacted<string>
readonly child: LauncherChildHandle
readonly ready: ReadyOptions | undefined
readonly phase: Ref.Ref<HandlePhase>
readonly gate: Semaphore.Semaphore
}) => Handle
makeHandle({
node: AnyNodenode: spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec.SpawnSpec.node: AnyNodenode,
token: Redacted.Redacted<string>(property) token: {
label: 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; <…;
}
token,
child: ChildProcessSpawner.ChildProcessHandle(property) child: {
pid: ProcessId;
exitCode: Effect.Effect<ExitCode, PlatformError.PlatformError>;
isRunning: Effect.Effect<boolean, PlatformError.PlatformError>;
kill: (options?: KillOptions | undefined) => Effect.Effect<void, PlatformError.PlatformError>;
stdin: Sink.Sink<void, Uint8Array, never, PlatformError.PlatformError>;
stdout: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
stderr: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
all: Stream.Stream<Uint8Array, PlatformError.PlatformError>;
getInputFd: (fd: number) => Sink.Sink<void, Uint8Array, never, PlatformError.PlatformError>;
getOutputFd: (fd: number) => Stream.Stream<Uint8Array, PlatformError.PlatformError>;
unref: Effect.Effect<Reref, PlatformError.PlatformError>;
}
child,
ready: ReadyOptions | undefinedready: spec: SpawnSpec(parameter) spec: {
node: AnyNode;
process: ChildProcess.Command | ((token: string) => ChildProcess.Command);
ready: ReadyOptions;
}
spec.SpawnSpec.ready?: ReadyOptionsready,
phase: Ref.Ref<HandlePhase>(property) phase: {
ref: MutableRef.MutableRef<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; <…;
}
phase,
gate: Semaphore.Semaphore(property) gate: {
resize: (this: Semaphore, permits: number) => Effect.Effect<void>;
withPermits: (this: Semaphore, permits: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
withPermit: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
withPermitsIfAvailable: (this: Semaphore, permits: number) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Option.Option<A>, E, R>;
take: (this: Semaphore, permits: number) => Effect.Effect<number>;
release: (this: Semaphore, permits: number) => Effect.Effect<number>;
releaseAll: Effect.Effect<number>;
}
gate,
});
}),
);