Context.Tag, Context.GenericTag, Effect.Tag, or Effect.Service. In v4, all of these have been replaced by ServiceMap.Service.
The underlying data structure has also changed: Context has been replaced by ServiceMap — a typed map from service identifiers to their implementations.
Defining Services
Function Syntax
Class-Based Services
Note the difference in argument order: in v3, the identifier string is passed to
Context.Tag(id) before the type parameters. In v4, the type parameters come first via ServiceMap.Service<Self, Shape>() and the identifier string is passed to the returned constructor (id).Migrating from Effect.Tag Accessors
v3’sEffect.Tag provided proxy access to service methods as static properties on the tag class (accessors). This allowed calling service methods directly without first yielding the service:
get<T>(key: string): Effect<T> would have its generic erased when accessed through the proxy, collapsing to get(key: string): Effect<unknown>.
Using Service.use
In v4, accessors are removed. The most direct replacement isService.use, which receives the service instance and runs a callback:
Service.use vs Service.useSync
use takes an effectful callback (service: Shape) => Effect<A, E, R> and returns an Effect<A, E, R | Identifier>. useSync takes a pure callback (service: Shape) => A and returns an Effect<A, never, Identifier>:
Best Practice: Use yield*
Usingyield* in a generator makes dependencies explicit and keeps service access co-located with the rest of your effect logic:
Migrating Effect.Service
v3’sEffect.Service allowed defining a service with an effectful constructor and dependencies inline. In v4, use ServiceMap.Service with a make option.
The
dependencies option no longer exists. Wire dependencies via Layer.provide as shown above.v4 adopts the convention of naming layers with layer (e.g. Logger.layer) instead of v3’s Default or Live. Use layer for the primary layer and descriptive suffixes for variants (e.g. layerTest, layerConfig).References (Services with Defaults)
Quick Reference
| v3 | v4 |
|---|---|
Context.GenericTag<T>(id) | ServiceMap.Service<T>(id) |
Context.Tag(id)<Self, Shape>() | ServiceMap.Service<Self, Shape>()(id) |
Effect.Tag(id)<Self, Shape>() | ServiceMap.Service<Self, Shape>()(id) |
Effect.Service<Self>()(id, opts) | ServiceMap.Service<Self>()(id, { make }) |
Context.Reference<Self>()(id, opts) | ServiceMap.Reference<T>(id, opts) |
Context.make(tag, impl) | ServiceMap.make(tag, impl) |
Context.get(ctx, tag) | ServiceMap.get(map, tag) |
Context.add(ctx, tag, impl) | ServiceMap.add(map, tag, impl) |
Context.mergeAll(...) | ServiceMap.mergeAll(...) |
Summary
The migration fromContext.Tag to ServiceMap.Service involves:
- Rename imports from
ContexttoServiceMap - Update service definitions to use
ServiceMap.Service - Replace accessor patterns with
yield*orService.use - Manually create layers for services with
make(no auto-generated.Default) - Use
layernaming convention instead ofDefaultorLive