1# Layer Memoization
2
3In v3, each call to `Effect.provide` created its own memoization scope. Layers
4were memoized / deduplicated within a single `Effect.provide` call, but would
5**not** be shared across separate calls — so two `Effect.provide` calls with
6overlapping layers would silently build those layers twice.
7
8In v4, the underlying `MemoMap` data structure which facilitates memoization of
9`Layer`s is shared between `Effect.provide` calls (unless explicitly disabled
10via the `{ local: true }` option). Thus, layers are automatically memoized /
11deduplicated across `Effect.provide` calls.
12
13## Example
14
15```ts
16import { Console, Context, Effect, Layer } from "effect"
17
18const MyService = Context.Service<{ readonly value: string }>("MyService")
19
20const MyServiceLayer = Layer.effect(
21 MyService,
22 Effect.gen(function*() {
23 yield* Console.log("Building MyService")
24 return { value: "hello" }
25 })
26)
27
28const program = Effect.gen(function*() {
29 const a = yield* MyService
30 return a.value
31})
32
33// Same layer provided twice in separate provide calls
34const main = program.pipe(
35 Effect.provide(MyServiceLayer),
36 Effect.provide(MyServiceLayer)
37)
38
39// Effect v3: "Building MyService" is logged TWICE
40// Effect v4: "Building MyService" is logged ONCE
41Effect.runPromise(main)
42```
43
44## Prefer Layer Composition Over Multipl Provides
45
46Even though v4 memoizes across `provide` calls, **composing layers before
47providing is still the recommended pattern**. Layer composition makes your
48dependency graph explicit and lets you see the full structure in one place:
49
50```ts
51// Preferred — provide once
52const main = program.pipe(Effect.provide(MyServiceLayer))
53```
54
55The auto-memoization feature is a safety net to avoid the footguns associated
56with multiple `Effect.provide` calls present in v3. It is **NOT** a substitute
57for proper layer composition.
58
59## Opting Out of Shared Memoization
60
61There are cases where you **want** a layer to be built fresh — for example,
62test isolation or creating independent resource pools. v4 provides two
63mechanisms:
64
65### `Layer.fresh`
66
67Wraps a layer so it always builds with a fresh memo map, bypassing the shared
68cache. This existed in v3 as well.
69
70```ts
71import { Effect, Layer } from "effect"
72
73const main = program.pipe(
74 Effect.provide(MyServiceLayer),
75 Effect.provide(Layer.fresh(MyServiceLayer))
76)
77// "Building MyService" is logged TWICE — fresh bypasses the shared cache
78```
79
80### `Effect.provide` with `{ local: true }`
81
82New in v4. Builds the provided layer with a **local memo map** instead of the
83fiber's shared one. The layer and all its sublayers are built from scratch and
84are not shared with other `provide` calls.
85
86```ts
87import { Effect } from "effect"
88
89const main = program.pipe(
90 Effect.provide(MyServiceLayer),
91 Effect.provide(MyServiceLayer, { local: true })
92)
93// "Building MyService" is logged TWICE — local creates its own memo map
94```
95
96Use `local: true` when you need an entire layer subtree to be isolated — for
97example, when providing layers in a test harness where each test should get
98independent resources.