Managing Layers
A layer is the recipe that builds a service. Layer<Out, Error, In> reads
like an effect: it produces the services Out, may fail with Error while
constructing them, and requires the services In to do so. Choosing the right
constructor depends on how the implementation comes to exist — a plain value, an
effectful setup, or a resource that must be released.
import { Context, Layer } from "effect"
class Greeter extends Context.Service<Greeter, { readonly greeting: string}>()("myapp/Greeter") {}
// `Layer.succeed` — the implementation is a value you already have.const GreeterLive = Layer.succeed(Greeter, { greeting: "Hello" })The three constructors
Section titled “The three constructors”Layer.succeed — a ready-made value
Section titled “Layer.succeed — a ready-made value”Use it when the service is just a plain object, with no setup work:
import { Context, Effect, Layer } from "effect"
class Config extends Context.Service<Config, { readonly apiUrl: string}>()("myapp/Config") {}
const ConfigLive = Layer.succeed(Config, { apiUrl: "https://api.example.com" })Layer.effect — effectful construction
Section titled “Layer.effect — effectful construction”Use it when building the service requires running an effect: reading config, allocating state, or depending on another service. The effect runs once, when the layer is built, and its result is memoized:
import { Context, Effect, Layer, Ref } from "effect"
class Counter extends Context.Service<Counter, { readonly increment: Effect.Effect<number>}>()("myapp/Counter") { static readonly layer = Layer.effect( Counter, Effect.gen(function*() { // Setup work runs once at build time — here, allocating shared state. const ref = yield* Ref.make(0)
const increment = Ref.updateAndGet(ref, (n) => n + 1)
return Counter.of({ increment }) }) )}Scoped layers — resources that must be released
Section titled “Scoped layers — resources that must be released”In Effect v4 there’s no separate Layer.scoped: Layer.effect already accepts
an effect that requires a Scope. Acquire the resource with
Effect.acquireRelease and the layer ties its cleanup to the layer’s own
lifetime — when the layer is torn down, the resource is released.
import { Context, Effect, Layer } from "effect"
class Pool extends Context.Service<Pool, { readonly run: <A>(work: () => A) => Effect.Effect<A>}>()("myapp/Pool") { static readonly layer = Layer.effect( Pool, Effect.gen(function*() { // acquireRelease pairs setup with a guaranteed release. The `Scope` it // introduces is absorbed by `Layer.effect`, so it never leaks into the // layer's requirements. const connections = yield* Effect.acquireRelease( Effect.sync(() => { // open the pool return { close: () => {} } }), (pool) => Effect.sync(() => pool.close()) )
const run = <A>(work: () => A) => Effect.sync(() => work()) return Pool.of({ run }) }) )}Providing a layer
Section titled “Providing a layer”A layer is inert until you attach it to a program. Effect.provide discharges
the matching requirements and returns an effect that no longer needs them:
import { Effect } from "effect"import { Counter } from "./Counter.ts"
const program = Effect.gen(function*() { const counter = yield* Counter yield* counter.increment return yield* counter.increment // 2})
// After providing, the `Counter` requirement is gone and the effect can run.const runnable: Effect.Effect<number> = program.pipe( Effect.provide(Counter.layer))
Effect.runFork(runnable)For programs whose whole point is the layer’s lifecycle — a server that should
stay up until interrupted — Layer.launch builds the layer and keeps it alive:
import { Effect, Layer } from "effect"import { Pool } from "./Pool.ts"
// Builds Pool.layer, holds it open forever, and releases on interruption.Effect.runFork(Layer.launch(Pool.layer))Which constructor?
Section titled “Which constructor?”| Constructor | When |
| --- | --- |
| Layer.succeed | The service is a plain value, no setup needed |
| Layer.sync | Same, but build it lazily at layer-build time |
| Layer.effect | Construction is effectful or depends on other services |
| Layer.effect + Effect.acquireRelease | The service owns a resource to release |
| Layer.mergeAll | Combine several independent layers into one |
Next, see how layers depend on one another in Layer composition.