# Layer composition makes dependencies explicit

> For agents: start with the [agent guide](https://ratstack.sh/llms.txt). Every page is Markdown by default; add `Accept: text/html` for HTML.

Free workshop: [how to burn a trillion tokens and get good results](/tokenmaxx#interested).

A Layer describes how to build a service from other services.
Compose the graph before running the application. Keep dependencies private unless callers need them too.

## Supply dependencies without changing the domain

`FileInspector.layer` needs a filesystem implementation.
`NodeServices.layer` supplies platform services. The CLI combines them before execution.

apps/cli/src/cli.ts at 65e9465f38092e24486392f22c08f45d61230c20; lines 16-25; highlighted none.

```typescript
  Effect.provide(
    Layer.mergeAll(
      Layer.provideMerge(FileInspector.layer, NodeServices.layer),
      remoteJoinInterestLayer,
      Approval.denyAll
    )
  )
);

NodeRuntime.runMain(program);
```

Choose the combinator by the services the resulting Layer should expose:

| Combinator                       | What the resulting Layer exposes                                |
| -------------------------------- | --------------------------------------------------------------- |
| `Layer.provide(dependency)`      | The consuming Layer's services                                  |
| `Layer.provideMerge(dependency)` | The consuming Layer's services and the dependency's services    |
| `Layer.merge` or `mergeAll`      | The combined services; unrelated requirements remain unresolved |

Merging services does not, by itself, feed one Layer into another Layer's requirements.

The test suite retains platform services with `provideMerge` because tests also create temporary files.
Production callers that need only the inspector can keep its implementation dependency private with `provide`.

## Reuse Layer identity when sharing construction

Sharing follows Layer identity within a memoization context. Equivalent construction code does not make two Layer values identical.
Sharing is limited to that construction context.

The fixture gives two consumers a resource. One case shares a Layer value; the other calls the Layer factory again.

packages/core/test/layer-composition.test.ts at 72306d84e9b57f068f8e293c0d2f0c7b934338e1; lines 16-23; highlighted none.

```typescript
      const resource = Resource.layer();

      const graph = Layer.merge(
        ReadAccess.layer.pipe(Layer.provide(resource)),
        WriteAccess.layer.pipe(
          Layer.provide(shared ? resource : Resource.layer())
        )
      );
```

`Resource.layer()` creates a new Layer value. Reusing `resource` lets the two branches share construction.

The fixture counts constructions and compares service ids:

packages/core/test/layer-composition.test.ts at 72306d84e9b57f068f8e293c0d2f0c7b934338e1; lines 25-32; highlighted none.

```typescript
      const ids = yield* Effect.gen(function* readServiceIds() {
        return [yield* ReadAccess, yield* WriteAccess];
      }).pipe(Effect.provide(graph));

      const count = yield* ConstructionCount;

      expect(yield* Ref.get(count)).toBe(constructions);
      expect(ids[0] === ids[1]).toBe(shared);
```

Independent application runtimes do not share instances merely because they import the same Layer value.
Their construction context and memo-map lifetime matter too.

## Common wrong approach

Calling a Layer factory twice can create two pools, caches, or background workers when one shared instance was intended.
Keep the constructed Layer value and provide that same value to both consumers.

Do not use `provideMerge` everywhere to silence missing-service errors.
Read which services callers need. Retaining every dependency exposes implementation details and makes removal harder.

## Effect idiom and house rule

- Layers carry output services, construction failures, and input requirements. Composition resolves the requirements.
- In rat-stack, each entrypoint owns its composition root. A cartridge must pull out without breaking unrelated packages.
- The application chooses its workspace layout and adapter package boundaries.

See also: [service construction](/lore/services-capture-dependencies), [domain structure](/lore/structure-effect-by-domain), [cartridges](/lore/cartridges), and [testing](/lore/tests-that-earn-their-place).

## Sources

1. [Effect contributors. 2026. Layer. Effect 4.0.0.](https://github.com/Effect-TS/effect/blob/67ba4e46a11ccda0b6761578bfd22c04ae00167d/packages/effect/src/Layer.ts)
   Effect-TS. provide supplies dependencies; provideMerge retains their services; memoization uses Layer identity and a MemoMap. Accessed 2026-10-06.

2. [Effect contributors. 2026. Layer tests.](https://github.com/Effect-TS/effect/blob/67ba4e46a11ccda0b6761578bfd22c04ae00167d/packages/effect/test/Layer.test.ts)
   Effect-TS. Tests establish shared construction and resource lifetime within memoization contexts. Accessed 2026-10-06.

3. [rat-stack contributors. 2026. CLI composition root.](https://github.com/joelhooks/rat-stack/blob/65e9465f38092e24486392f22c08f45d61230c20/apps/cli/src/cli.ts)
   rat-stack. The CLI provides FileInspector and platform services before NodeRuntime.runMain. Accessed 2026-10-06.

4. [rat-stack contributors. 2026. Layer identity fixture.](https://github.com/joelhooks/rat-stack/blob/72306d84e9b57f068f8e293c0d2f0c7b934338e1/packages/core/test/layer-composition.test.ts)
   rat-stack. A checked seam fixture counts one construction for shared identity and two for separate Layer instances. Accessed 2026-10-06.

5. [Langton, Kit. 2026. Services & Layers. Effect Solutions.](https://github.com/kitlangton/effect-solutions/blob/09f82e6c5c928e7232cd32daf04d7c6a830b63f7/packages/website/docs/04-services-and-layers.md)
   Kit Langton. Topic framing for provision and identity-based Layer sharing; rewritten around rat-stack's code. Accessed 2026-10-06.

## Lore on this page

- [Structure an Effect codebase by domain](/lore/structure-effect-by-domain)
- [Cartridges](/lore/cartridges)

## Linked from

- A service captures its construction dependencies → Build a service with its dependencies, then expose methods that callers can use without rebuilding the graph. → [Read page](https://ratstack.sh/lore/services-capture-dependencies)

- Agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms.txt)

- Change log → What changed in the files served here, newest first. → [Read page](https://ratstack.sh/log)

- Configuration is a supplied, validated dependency → Parse configuration when a Layer builds, reject invalid values, and supply controlled settings in tests. → [Read page](https://ratstack.sh/lore/configuration-is-a-dependency)

- Effect basics → An Effect describes work, expected failures, and required services before a runtime executes it. → [Read page](https://ratstack.sh/lore/effect-basics)

- Effect keeps the surfaces on one contract → Schema owns values, projections build interfaces, and Layers supply implementations. → [Read page](https://ratstack.sh/lore/how-we-do-it-with-effect)

- Full agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms-full.txt)

- learn-rat-stack → Trace a capability through Effect, XState, five projections, the CLI, and Alchemy. Try hosted search and read. → [Read page](https://ratstack.sh/skills/learn-rat-stack)

- Rat Stack lore | rat-stack → Short, source-grounded notes on the ideas and decisions behind rat-stack. → [Read page](https://ratstack.sh/lore)

- Scopes release resources when work ends → Acquire resources lazily, keep their use inside the owner, and release them after success, failure, or interruption. → [Read page](https://ratstack.sh/lore/scopes-own-resources)

- Source change history (log.md) → The generated change log as Markdown. → [Read page](https://ratstack.sh/log.md)

- Structure an Effect codebase by domain → Start with domain folders, colocated services and Layers, and one composition root per entrypoint. → [Read page](https://ratstack.sh/lore/structure-effect-by-domain)
