(
target?: number | string,
serialization?: Layer.Layer<RpcSerialization.RpcSerialization>
): Layer.Layer<RpcClient.Protocol>Build an http client Protocol (Fetch + ndjson serialization) for an endpoint — the value you
hand layerProtocol or connect. target is a port (3009 → http://${clientHost}:3009/rpc,
Config host default "localhost"), a full url, or a same-origin path (default "/rpc"). The
server/CLI transport; a browser should prefer protocolWebsocket (HTTP/1.1's ~6-connection cap
starves streams — protocolHttp dies loudly in a browser).
export const const protocolHttp: (
target?: number | string,
serialization?: Layer.Layer<RpcSerialization.RpcSerialization>
) => Layer.Layer<RpcClient.Protocol>
Build an http client Protocol (Fetch + ndjson serialization) for an endpoint — the value you
hand
layerProtocol
or
connect
. target is a port (3009 → http://${clientHost}:3009/rpc,
Config host default "localhost"), a full url, or a same-origin path (default "/rpc"). The
server/CLI transport; a browser should prefer
protocolWebsocket
(HTTP/1.1's ~6-connection cap
starves streams — protocolHttp dies loudly in a browser).
protocolHttp = (
target: string | numbertarget: number | string = "/rpc",
serialization: Layer.Layer<
RpcSerialization.RpcSerialization,
never,
never
>
(parameter) serialization: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<RpcSerialization.RpcSerialization>, never, never>;
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; <…;
}
serialization: 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<import RpcSerializationRpcSerialization.class RpcSerializationclass RpcSerialization {
key: Identifier;
Service: {
makeUnsafe: () => RpcSerialization.Parser;
contentType: string;
includesFraming: boolean;
};
}
Service that describes how RPC protocol messages are encoded and decoded,
including the content type and whether the serialization format provides
message framing.
When to use
Use to provide the serialization boundary shared by RPC clients and servers
for a chosen wire format.
RpcSerialization> = const defaultSerialization: Layer.Layer<
RpcSerialization.RpcSerialization,
never,
never
>
const defaultSerialization: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<RpcSerialization.RpcSerialization>, never, never>;
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; <…;
}
defaultSerialization,
): 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<import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol> => {
// guard at the root: `http` / `connect` all build on this, so the browser footgun is closed for
// every http-client path in one place.
const const build: (
url: string
) => Layer.Layer<RpcClient.Protocol>
build = (url: stringurl: string): 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<import RpcClientRpcClient.class Protocolclass Protocol {
key: Identifier;
Service: {
run: (clientId: number, f: (data: FromServerEncoded) => Effect.Effect<void>) => Effect.Effect<never>;
send: (clientId: number, request: FromClientEncoded, transferables?: ReadonlyArray<globalThis.Transferable>) => Effect.Effect<void, RpcClientError>;
supportsAck: boolean;
supportsTransferables: boolean;
};
}
Defines the service interface for an RPC client transport, responsible for running the
receive loop and sending encoded client messages.
When to use
Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
workers, sockets, or custom protocols.
Protocol> =>
import LayerLayer.const merge: <never, never, RpcClient.Protocol, never, never, never>(self: Layer.Layer<RpcClient.Protocol, never, never>, that: Layer.Layer<never, never, never>) => Layer.Layer<RpcClient.Protocol, never, never> (+3 overloads)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 RpcClientRpcClient.const layerProtocolHttp: (options: {
readonly url: string
readonly transformClient?: <E, R>(
client: HttpClient.HttpClient.With<E, R>
) => HttpClient.HttpClient.With<E, R>
}) => Layer.Layer<
RpcClient.Protocol,
never,
| RpcSerialization.RpcSerialization
| HttpClient.HttpClient
>
Provides a client Protocol backed by HttpClient, targeting the configured
URL and optionally transforming the client before use.
layerProtocolHttp({ url: stringurl }).Pipeable.pipe<Layer.Layer<RpcClient.Protocol, never, RpcSerialization.RpcSerialization | HttpClient.HttpClient>, Layer.Layer<RpcClient.Protocol, never, HttpClient.HttpClient>, Layer.Layer<RpcClient.Protocol, never, never>>(this: Layer.Layer<...>, ab: (_: Layer.Layer<RpcClient.Protocol, never, RpcSerialization.RpcSerialization | HttpClient.HttpClient>) => Layer.Layer<RpcClient.Protocol, never, HttpClient.HttpClient>, bc: (_: Layer.Layer<...>) => Layer.Layer<...>): Layer.Layer<...> (+21 overloads)pipe(
import LayerLayer.const provide: <never, never, RpcSerialization.RpcSerialization>(that: Layer.Layer<RpcSerialization.RpcSerialization, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, RpcSerialization.RpcSerialization>> (+3 overloads)Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(serialization: Layer.Layer<
RpcSerialization.RpcSerialization,
never,
never
>
(parameter) serialization: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<RpcSerialization.RpcSerialization>, never, never>;
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; <…;
}
serialization),
import LayerLayer.const provide: <never, never, HttpClient.HttpClient>(that: Layer.Layer<HttpClient.HttpClient, never, never>) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E2, Exclude<RIn2, HttpClient.HttpClient>> (+3 overloads)Feeds the output services of the dependency layer into the requirements of
this layer, returning a layer that only provides the services from this layer.
When to use
Use when you need to hide an implementation dependency layer from callers.
Details
In serviceLayer.pipe(Layer.provide(dependencyLayer)), the dependency layer is
built first and is used to satisfy the requirements of serviceLayer.
Example (Providing layer dependencies)
import { Context, Effect, Layer } from "effect"
class Database extends Context.Service<Database, {
readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class UserService extends Context.Service<UserService, {
readonly getUser: (id: string) => Effect.Effect<{
id: string
name: string
}>
}>()("UserService") {}
class Logger extends Context.Service<Logger, {
readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}
// Create dependency layers
const databaseLayer = Layer.succeed(Database, {
query: Effect.fn("Database.query")((sql: string) => Effect.succeed(`DB: ${sql}`))
})
const loggerLayer = Layer.succeed(Logger, {
log: Effect.fn("Logger.log")((msg: string) => Effect.sync(() => console.log(`[LOG] ${msg}`)))
})
// UserService depends on Database and Logger
const userServiceLayer = Layer.effect(UserService, Effect.gen(function*() {
const database = yield* Database
const logger = yield* Logger
return {
getUser: Effect.fn("UserService.getUser")(function*(id: string) {
yield* logger.log(`Looking up user ${id}`)
const result = yield* database.query(
`SELECT * FROM users WHERE id = ${id}`
)
return { id, name: result }
})
}
}))
// Provide dependencies to UserService layer
const userServiceWithDependencies = userServiceLayer.pipe(
Layer.provide(Layer.mergeAll(databaseLayer, loggerLayer))
)
// Now UserService layer has no dependencies
const program = Effect.gen(function*() {
const userService = yield* UserService
return yield* userService.getUser("123")
}).pipe(
Effect.provide(userServiceWithDependencies)
)
provide(import FetchHttpClientFetchHttpClient.const layer: Layer.Layer<
HttpClient.HttpClient,
never,
never
>
const layer: {
build: (memoMap: Layer.MemoMap, scope: Scope.Scope) => Effect.Effect<Context.Context<HttpClient.HttpClient>, never, never>;
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; <…;
}
Layer that provides an HttpClient implementation backed by the configured
Fetch function.
When to use
Use when an Effect program should execute HttpClient requests through the
platform fetch implementation, especially in browser, edge, or Node.js
runtimes with globalThis.fetch.
Details
The layer uses the current Fetch reference and optional RequestInit
service for each request. Request-specific method, headers, body, and abort
signal are supplied by the client and override matching RequestInit fields.
Gotchas
Fetch behavior comes from the runtime's implementation, so CORS, cookies,
redirects, abort handling, and streaming support can vary by platform. Stream
request bodies are sent as Web streams with duplex: "half", and any
content-length header is removed before calling fetch.
layer),
),
import LayerLayer.const effectDiscard: <void, never, never>(effect: Effect.Effect<void, never, never>) => Layer.Layer<never, never, never>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(const dieIfHttpClientInBrowser: Effect.Effect<
void,
never,
never
>
const dieIfHttpClientInBrowser: {
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;
}
dieIfHttpClientInBrowser),
);
// A bare port defers to the `clientHost` Config (layer build); a path / url stays sync.
return typeof target: string | numbertarget === "number" || /^:\d+$/.RegExp.test(string: string): booleanReturns a Boolean value that indicates whether or not a pattern exists in a searched string.
test(target: stringtarget)
? import LayerLayer.const unwrap: <RpcClient.Protocol, never, never, never, never>(self: Effect.Effect<Layer.Layer<RpcClient.Protocol, never, never>, never, never>) => Layer.Layer<RpcClient.Protocol, never, never>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 map: <string, never, never, Layer.Layer<RpcClient.Protocol, never, never>>(self: Effect.Effect<string, never, never>, f: (a: string) => Layer.Layer<RpcClient.Protocol, never, never>) => Effect.Effect<Layer.Layer<RpcClient.Protocol, never, never>, never, never> (+1 overload)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(const clientTargetUrl: (
scheme: "http" | "ws",
target: number | string
) => Effect.Effect<string>
A bare port (3009) / ":3009" resolves to ${scheme}://${clientHost}:port/rpc (Config host,
read at layer build); a path / full url passes through unchanged.
clientTargetUrl("http", target: string | numbertarget), const build: (
url: string
) => Layer.Layer<RpcClient.Protocol>
build))
: const build: (
url: string
) => Layer.Layer<RpcClient.Protocol>
build(target: stringtarget);
};