# Building 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.

```ts
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" })
```

Layers are **lazy** (nothing runs until the layer is provided, built, or
launched), **scoped** (finalizers run when the owning scope closes), and
**memoized by default** (the same layer value, shared across a graph, acquires a
single instance of its service).

## The three constructors

### `Layer.succeed` — a ready-made value

Use it when the service is just a plain object, with no setup work:

```ts
import { Context, 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

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:

```ts
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

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.

```ts
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 })
    })
  )
}
```
**Note:** Returning a resource acquired with `Effect.acquireRelease` (or registering a
finalizer with `Effect.addFinalizer`) inside `Layer.effect` ties that finalizer
to the **layer scope**. The `Scope` requirement those APIs introduce is consumed
by `Layer.effect` and never appears in the layer's `In` type. Acquisition and
release are covered in depth in [Resource Management](https://effect.plants.sh/resource-management/);
the key idea here: a layer is the natural place to own a resource, because its
scope spans your whole application.

## 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:

```ts
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)
```

`Effect.provide` attaches a layer to an **effect**. `Layer.provide` instead feeds
one layer's output into another layer's requirements, producing a new layer —
that's how you wire dependencies between services and is covered in
[Layer composition](https://effect.plants.sh/services-and-layers/layer-composition/).

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:

```ts
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?

| 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.effectDiscard` | Run setup work / background tasks, provide nothing |
| `Layer.suspend` | Defer construction; choose or break a cycle at build time |
| `Layer.unwrap` | Pick the concrete layer from an `Effect` (e.g. from config) |
| `Layer.mergeAll` | Combine several independent layers into one |
**Tip:** There's no auto-generated `.layer` on a `Context.Service` class — the `Counter.layer`
above is a `static` you define yourself, which is the idiomatic v4 convention.
You *can* pass a `make` effect to the class (`Context.Service<Self, Shape>()("Id",
{ make })`), which attaches it as `Self.make`; you then lift it once with
`static layer = Layer.effect(Self, Self.make)`.

## Memoization and sharing

By default a layer **value** is memoized: provide the same layer in two places
and the service is constructed once and shared. Sharing is keyed on layer
*identity*, so constructing the same recipe twice yields two distinct values that
each acquire their own instance.

### `Layer.fresh`

Forces a layer to be rebuilt even if the same value is provided more than once —
use it when two parts of the app must get *separate* instances (e.g. two
independent client sessions).

```ts
import { Context, Effect, Layer, Ref } from "effect"

class Counter extends Context.Service<Counter, { readonly id: number }>()("Counter") {}

const program = Effect.gen(function*() {
  const next = yield* Ref.make(0)
  const counterLayer = Layer.effect(
    Counter,
    Effect.gen(function*() {
      const id = yield* Ref.updateAndGet(next, (n) => n + 1)
      return { id }
    })
  )

  // `counterLayer` shared => one instance; `Layer.fresh(counterLayer)` => a new one.
  return Layer.fresh(counterLayer)
})
```
**Note:** `Layer.build`, `buildWithScope`, and friends accept an explicit `MemoMap`
(`Layer.makeMemoMap`, `Layer.buildWithMemoMap`) when you need to control sharing
across several manual builds. This is advanced wiring; the default behavior is
what you want most of the time.

## Layer constructors reference

Every constructor below produces a `Layer`. Constructors come in a *single-service*
form (you pass a `Context.Key`/service class and a value/effect) and a *whole-context*
form (the `*Context` variants) that can provide several services at once.

### `Layer.succeed`

Provides one already-constructed service value. Also supports a curried "key
first" form for use in a `pipe`.

```ts
import { Context, Layer } from "effect"

class Config extends Context.Service<Config, { readonly port: number }>()("Config") {}

const ConfigLive = Layer.succeed(Config, { port: 8080 })
// => Layer<Config>

// Curried (data-last) form — handy when piping a value in:
const fromValue = ({ port: 8080 } as const).pipe(Layer.succeed(Config))
// => Layer<Config>
```

### `Layer.succeedContext`

Provides every service contained in an already-built `Context`. Use it when you
have a multi-service `Context` value rather than a single implementation.

```ts
import { Context, Effect, Layer } from "effect"

class Config extends Context.Service<Config, { readonly port: number }>()("Config") {}
class Logger extends Context.Service<Logger, {
  readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}

const context = Context.make(Config, { port: 8080 }).pipe(
  Context.add(Logger, { log: (msg) => Effect.sync(() => console.log(msg)) })
)

const Live = Layer.succeedContext(context)
// => Layer<Config | Logger>
```

### `Layer.sync`

Lazily builds one service value with a thunk that runs at layer-build time. Use
it instead of `succeed` when the value should not be computed until the layer is
actually built (e.g. it reads `Date.now()` or allocates a mutable cell).

```ts
import { Context, Layer } from "effect"

class Clock extends Context.Service<Clock, { readonly startedAt: number }>()("Clock") {}

const ClockLive = Layer.sync(Clock, () => ({ startedAt: Date.now() }))
// => Layer<Clock>  (the thunk runs when the layer is built, not now)
```

### `Layer.syncContext`

The lazy, whole-`Context` version of `succeedContext`: the factory runs at
build time and returns a `Context` of one or more services.

```ts
import { Context, Layer } from "effect"

class Config extends Context.Service<Config, { readonly env: string }>()("Config") {}

const Live = Layer.syncContext(() =>
  Context.make(Config, { env: process.env.NODE_ENV ?? "development" })
)
// => Layer<Config>
```

### `Layer.effect`

Builds one service from an `Effect`, run once when the layer is built. The
effect can depend on other services and acquire scoped resources; any `Scope`
requirement is absorbed (it does not appear in the layer's `In` type), and a
typed failure becomes the layer's `Error`.

```ts
import { Context, Effect, Layer } from "effect"

class Database extends Context.Service<Database, {
  readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}

const DatabaseLive = Layer.effect(
  Database,
  Effect.gen(function*() {
    yield* Effect.log("connecting…")
    return Database.of({ query: (sql) => Effect.succeed(`rows for: ${sql}`) })
  })
)
// => Layer<Database, never, never>
```

### `Layer.effectContext`

The whole-`Context` version of `effect`: the effect produces a `Context` of one
or more services. Use it when a single effectful setup builds several services
together.

```ts
import { Context, Effect, Layer } from "effect"

class Database extends Context.Service<Database, {
  readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}
class Cache extends Context.Service<Cache, {
  readonly get: (k: string) => Effect.Effect<string>
}>()("Cache") {}

const Live = Layer.effectContext(
  Effect.gen(function*() {
    const db = Database.of({ query: (sql) => Effect.succeed(`rows: ${sql}`) })
    const cache = Cache.of({ get: (k) => Effect.succeed(`cached: ${k}`) })
    return Context.make(Database, db).pipe(Context.add(Cache, cache))
  })
)
// => Layer<Database | Cache>
```

### `Layer.effectDiscard`

Runs an effect for its side effects during layer construction and provides **no**
services (`Out` is `never`). Ideal for startup logging, warm-up work, or spawning
a background fiber whose lifetime is tied to the layer scope.

```ts
import { Effect, Layer } from "effect"

const BackgroundTask = Layer.effectDiscard(
  Effect.gen(function*() {
    yield* Effect.log("starting background task…")
    yield* Effect.gen(function*() {
      while (true) {
        yield* Effect.sleep("5 seconds")
        yield* Effect.log("tick")
      }
    }).pipe(Effect.forkScoped) // interrupted when the layer scope closes
  })
)
// => Layer<never>  — provides nothing, just runs work
```

### `Layer.empty`

A no-op layer: provides nothing, never fails, has no requirements, and does no
construction or finalization. Useful as the inert branch when conditionally
composing layers.

```ts
import { Console, Layer } from "effect"

declare const verbose: boolean

const StartupLog = verbose
  ? Layer.effectDiscard(Console.log("starting"))
  : Layer.empty
// => Layer<never>
```

### `Layer.suspend`

Defers the construction of a layer until it is first built; the factory's result
is then memoized with normal sharing semantics. New in v4 — use it to choose a
layer based on build-time state, or to break an initialization cycle by deferring
a reference to a layer defined later.

```ts
import { Context, Layer } from "effect"

class Config extends Context.Service<Config, string>()("Config") {}

declare const useProd: boolean

const ConfigLive = Layer.suspend(() =>
  useProd
    ? Layer.succeed(Config, "https://api.example.com")
    : Layer.succeed(Config, "http://localhost:3000")
)
// => Layer<Config>  — the branch is chosen when the layer is built
```

### `Layer.unwrap`

Flattens an `Effect` that produces a `Layer` into a single layer, combining both
error and requirement channels. This is the canonical way to choose a concrete
implementation from configuration: read config in the effect, then return the
layer to use.

```ts
import { Config, Context, Effect, Layer } from "effect"

class MessageStore extends Context.Service<MessageStore, {
  readonly append: (msg: string) => Effect.Effect<void>
}>()("MessageStore") {
  static readonly layerInMemory = Layer.sync(MessageStore, () => {
    const messages: Array<string> = []
    return MessageStore.of({ append: (msg) => Effect.sync(() => { messages.push(msg) }) })
  })

  static readonly layerNoop = Layer.succeed(MessageStore, {
    append: () => Effect.void
  })

  // Choose the concrete layer at build time, based on an env var.
  static readonly layer = Layer.unwrap(
    Effect.gen(function*() {
      const inMemory = yield* Config.boolean("IN_MEMORY").pipe(Config.withDefault(true))
      return inMemory ? MessageStore.layerInMemory : MessageStore.layerNoop
    })
  )
}
// => Layer<MessageStore, ConfigError>
```

Building a layer from configuration is common enough that it has its own page —
see [Layers from config](https://effect.plants.sh/services-and-layers/layer-from-config/).

### `Layer.fromBuild` / `Layer.fromBuildMemo`

Low-level escape hatches that construct a layer from a function receiving a
`MemoMap` and a `Scope`. `fromBuildMemo` adds automatic memoization keyed on the
returned layer value. Most code never needs these — they back the higher-level
constructors above.

```ts
import { Context, Effect, Layer } from "effect"

class Database extends Context.Service<Database, {
  readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}

const DatabaseLive = Layer.fromBuild(() =>
  Effect.sync(() => Context.make(Database, { query: (sql) => Effect.succeed("result") }))
)
// => Layer<Database>
```

## Building a layer manually

Usually you hand a layer to `Effect.provide` and let the runtime build it. When
you need the produced `Context` directly — testing, wiring custom runtimes —
build it yourself.

### `Layer.build`

Builds the layer into its `Context`, using the ambient `Scope` and memo map. The
returned effect requires a `Scope`, so resources live until that scope closes.

```ts
import { Context, Effect, Layer } from "effect"

class Database extends Context.Service<Database, {
  readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}

const program = Effect.gen(function*() {
  const context = yield* Layer.build(Database.layer)
  const db = Context.get(context, Database)
  return yield* db.query("SELECT 1")
}).pipe(Effect.scoped) // closing this scope releases the layer
```

### `Layer.buildWithScope`

Like `build`, but you pass the `Scope` explicitly, giving you direct control over
when the layer's resources are released.

```ts
import { Context, Effect, Layer } from "effect"

declare const SomeLayer: Layer.Layer<unknown>

const program = Effect.gen(function*() {
  const scope = yield* Effect.scope
  const context = yield* Layer.buildWithScope(SomeLayer, scope)
  return context
})
```

### `Layer.launch`

Builds the layer and blocks forever, keeping it alive until the fiber is
interrupted — at which point the layer scope closes and finalizers run. This is
how "the whole app is a layer" programs (servers, daemons) are run.

```ts
import { Effect, Layer } from "effect"
import { Pool } from "./Pool.ts"

Effect.runFork(Layer.launch(Pool.layer))
// runs until interrupted, then releases Pool
```

## Observing and transforming construction

These combinators take a layer and return a layer, letting you react to success
or failure during construction without changing the services provided.

### `Layer.tap` / `Layer.tapError` / `Layer.tapCause`

Run an effect when the layer succeeds (`tap`, receiving the produced `Context`),
fails with a typed error (`tapError`), or fails with any `Cause` (`tapCause`).
The layer's output and error are preserved.

```ts
import { Context, Effect, Layer } from "effect"

class Database extends Context.Service<Database, { readonly url: string }>()("Database") {}

const DatabaseLive = Layer.succeed(Database, { url: "postgres://…" }).pipe(
  Layer.tap((ctx) => Effect.log(`connected to ${Context.get(ctx, Database).url}`)),
  Layer.tapError((e) => Effect.log(`build failed: ${e}`))
)
```

### `Layer.catch` / `Layer.catchTag` / `Layer.catchCause`

Recover from a construction failure by switching to another layer. `catch`
handles every typed error, `catchTag` matches specific tagged errors, and
`catchCause` receives the full `Cause` (defects, interruption included).

```ts
import { Context, Effect, Layer } from "effect"

class Config extends Context.Service<Config, { readonly apiUrl: string }>()("Config") {}

const primary = Layer.effect(Config, Effect.fail("boom" as const))
const recovered = primary.pipe(
  Layer.catch(() => Layer.succeed(Config, { apiUrl: "http://localhost" }))
)
// => Layer<Config>  — falls back instead of failing
```

### `Layer.orDie`

Converts every typed construction failure into an unrecoverable defect, removing
the error from the layer's type. Use only when a failure here means the program
cannot meaningfully continue.

```ts
import { Context, Effect, Layer } from "effect"

class Config extends Context.Service<Config, { readonly apiUrl: string }>()("Config") {}

const layer = Layer.effect(Config, Effect.fail("missing config" as const)).pipe(
  Layer.orDie
)
// => Layer<Config, never>  — failure becomes a defect
```

### `Layer.updateService`

Replaces a service in the layer's required context with a transformed version —
useful for adapting or wrapping an existing service implementation during
construction.

```ts
import { Context, Effect, Layer } from "effect"

class Logger extends Context.Service<Logger, {
  readonly log: (msg: string) => Effect.Effect<void>
}>()("Logger") {}

declare const AppLayer: Layer.Layer<unknown, never, Logger>

const withPrefixedLogger = AppLayer.pipe(
  Layer.updateService(Logger, (logger) => ({
    log: (msg) => logger.log(`[app] ${msg}`)
  }))
)
```

## Testing helpers

### `Layer.mock`

Builds a layer from a *partial* service implementation: any omitted member that
is an `Effect`, `Stream`, `Channel`, or function returning one fails with an
`UnimplementedError` if exercised, while non-effect properties remain required.

```ts
import { Context, Effect, Layer } from "effect"

class UserService extends Context.Service<UserService, {
  readonly config: { apiUrl: string }
  readonly getUser: (id: string) => Effect.Effect<{ id: string; name: string }>
  readonly deleteUser: (id: string) => Effect.Effect<void>
}>()("UserService") {}

const testLayer = Layer.mock(UserService, {
  config: { apiUrl: "https://test" },        // required, non-effect property
  getUser: (id) => Effect.succeed({ id, name: "Test" })
  // deleteUser omitted — throws UnimplementedError if called
})
// => Layer<UserService>
```

## Tracing during construction

`Layer.span`, `Layer.withSpan`, `Layer.parentSpan`, and `Layer.withParentSpan`
wrap layer construction in a trace span so that all setup work is attributed to a
named span that ends when the layer scope closes.

```ts
import { Context, Effect, Layer } from "effect"

class Database extends Context.Service<Database, {
  readonly query: (sql: string) => Effect.Effect<string>
}>()("Database") {}

const DatabaseLive = Layer.effect(
  Database,
  Effect.gen(function*() {
    yield* Effect.log("connecting") // traced under "db-init"
    return Database.of({ query: (sql) => Effect.succeed(`rows: ${sql}`) })
  })
).pipe(Layer.withSpan("db-init", { attributes: { dbType: "postgres" } }))
```

## Type utilities

A handful of type-level helpers extract a layer's components or constrain it:

- `Layer.Success<L>` — the services a layer provides (`Out`).
- `Layer.Error<L>` — the construction error type (`Error`).
- `Layer.Services<L>` — the dependency requirements (`In`).
- `Layer.satisfiesSuccessType<T>()` / `satisfiesErrorType<T>()` /
  `satisfiesServicesType<T>()` — compile-time assertions that a layer's `Out`,
  `Error`, or `In` extends `T`.

```ts
import { Layer } from "effect"

declare const AppLayer: Layer.Layer<{ db: unknown }, Error, { config: unknown }>

type Provided = Layer.Success<typeof AppLayer> // { db: unknown }
type Fails = Layer.Error<typeof AppLayer>       // Error
type Needs = Layer.Services<typeof AppLayer>    // { config: unknown }
```

Next, see how layers depend on one another and how to wire dependency graphs in
[Layer composition](https://effect.plants.sh/services-and-layers/layer-composition/).