LayerMap
Caches scoped services selected by key and built from layers.
A LayerMap<K, I, E> turns a key into a cached service Context<I> and
exposes that context as either a Layer or a scoped effect. Entries can be
invalidated explicitly or released after they sit unused. This is useful for
keyed resource families such as tenant clients, regional connections, or
environment-specific services.
Constructors
fromRecord
Creates a LayerMap from a record of predefined layers.
Details
The record keys become the keys accepted by the returned LayerMap, and the
record values are the layers built for those keys.
Signature
declare function fromRecord<Layers extends Record<string, Layer<any, any, any>>, Preload extends boolean = false>(layers: Layers, options?: { readonly idleTimeToLive?: IdleTimeToLiveInput<keyof Layers>; readonly preload?: Preload;}): Effect<LayerMap<keyof Layers, Success<Layers[keyof Layers]>, Error<Layers[keyof Layers]>>, Preload extends true ? Error<Layers[keyof Layers]> : never, Scope | Layers[keyof Layers] extends Layer<_A, _E, _R> ? _R : never>Example
(Creating a layer map from a record)
import { Context, Effect, Layer, LayerMap } from "effect"
// Define a service keyconst Database = Context.Service<{ readonly query: (sql: string) => Effect.Effect<string>}>("Database")
// Create predefined layersconst layers = { development: Layer.succeed(Database)({ query: Effect.fn("DevDatabase.query")((sql) => Effect.succeed(`DEV: ${sql}`)) }), production: Layer.succeed(Database)({ query: Effect.fn("ProdDatabase.query")((sql) => Effect.succeed(`PROD: ${sql}`)) })} as const
// Create a LayerMap from the recordconst program = Effect.gen(function*() { const layerMap = yield* LayerMap.fromRecord(layers, { idleTimeToLive: "10 seconds" })
const development = yield* Effect.provide( Database.use((database) => database.query("SELECT 1")), layerMap.get("development") ) const production = yield* Effect.provide( Database.use((database) => database.query("SELECT 1")), layerMap.get("production") )
return { development, production }})
await Effect.runPromise(Effect.scoped(program)) // => { development: "DEV: SELECT 1", production: "PROD: SELECT 1" }Creates a LayerMap that dynamically provides resources based on a key.
Signature
declare const make: <K, L extends Layer.Layer<any, any, any>, PreloadKeys extends Iterable<K> | undefined = undefined>(lookup: (key: K) => L, options?: { readonly idleTimeToLive?: IdleTimeToLiveInput<K>; readonly preloadKeys?: PreloadKeys;}) => Effect.Effect<LayerMap<K, Layer.Success<L>, Layer.Error<L>>, PreloadKeys extends undefined ? never : Layer.Error<L>, Scope.Scope | Layer.Services<L>>Example
(Creating a layer map)
import { Context, Effect, Layer, LayerMap } from "effect"
// Define a service keyconst DatabaseService = Context.Service<{ readonly query: (sql: string) => Effect.Effect<string>}>("Database")
// Create a LayerMap that provides different database configurationsconst program = Effect.gen(function*() { const layerMap = yield* LayerMap.make( (env: string) => Layer.succeed(DatabaseService)({ query: Effect.fn("DatabaseService.query")((sql) => Effect.succeed(`${env}: ${sql}`)) }), { idleTimeToLive: "5 seconds" } )
// Get a layer for a specific environment const devLayer = layerMap.get("development")
// Use the layer to provide the service return yield* Effect.provide( Effect.gen(function*() { const db = yield* DatabaseService return yield* db.query("SELECT * FROM users") }), devLayer )})
await Effect.runPromise(Effect.scoped(program)) // => "development: SELECT * FROM users"Models
A scoped, keyed map of layer-built service contexts.
Details
A LayerMap builds resources for a key on demand, exposes them as a Layer
or scoped Context, and can invalidate cached resources for a key.
Signature
interface LayerMap<in out K, in out I, in out E = never> { readonly "~effect/LayerMap": "~effect/LayerMap"; readonly rcMap: RcMap<K, Context<I>, E>; contextEffect(key: K): Effect<Context<I>, E, Scope>; contextEffectOption(key: K): Effect<Option<Context<I>>, E, Scope>; get(key: K): Layer<I, E>; invalidate(key: K): Effect<void>;}Example
(Managing keyed layers)
import { Context, Effect, Layer, LayerMap } from "effect"
// Define a service keyconst DatabaseService = Context.Service<{ readonly query: (sql: string) => Effect.Effect<string>}>("Database")
// Create a LayerMap that provides different database configurationsconst createDatabaseLayerMap = LayerMap.make((env: string) => Layer.succeed(DatabaseService)({ query: Effect.fn("DatabaseService.query")((sql) => Effect.succeed(`${env}: ${sql}`)) }))
// Use the LayerMapconst program = Effect.gen(function*() { const layerMap = yield* createDatabaseLayerMap
// Get a layer for a specific environment const development = yield* Effect.provide( DatabaseService.use((database) => database.query("SELECT 1")), layerMap.get("development") )
// Get context directly const productionContext = yield* layerMap.contextEffect("production") const production = yield* Context.get(productionContext, DatabaseService).query("SELECT 1")
// Invalidate a cached layer yield* layerMap.invalidate("development")
return { development, production }})
await Effect.runPromise(Effect.scoped(program)) // => { development: "development: SELECT 1", production: "production: SELECT 1" }Other
Services
Create a LayerMap service that provides a dynamic set of resources based on
a key.
Signature
declare function Service<Self>(): <Id extends string, Options extends NoExcessProperties<{ readonly dependencies?: readonly Array<Layer<any, any, any>>; readonly idleTimeToLive?: IdleTimeToLiveInput<any>; readonly lookup: (key: any) => Layer<any, any, any>; readonly preloadKeys?: Iterable<Options extends { readonly lookup: (key: K) => any; } ? K : never, any, any>;}, Options> | NoExcessProperties<{ readonly dependencies?: readonly Array<Layer<any, any, any>>; readonly idleTimeToLive?: IdleTimeToLiveInput<any>; readonly layers: Record<string, Layer.Layer<any, any, any>>; readonly preload?: boolean;}, Options>>(id: Id, options: Options) => TagClass<Self, Id, Options extends { readonly lookup: (key: K) => any;} ? K : Options extends { readonly layers: Layers;} ? keyof Layers : never, Success<Options>, Options extends { readonly preload: true;} ? never : Error<Options>, Services<Options>, Options extends { readonly preload: true;} ? Error<Options> : Options extends { readonly preloadKeys: Iterable<any>;} ? Error<Options> : never, Options extends { readonly dependencies: readonly Array<Layer<any, any, any>>;} ? Options["dependencies"][number] : never>Example
(Defining a layer map service)
import { Context, Effect, Layer, LayerMap } from "effect"
// Define a service keyconst Greeter = Context.Service<{ readonly greet: Effect.Effect<string>}>("Greeter")
// Create a service that wraps a LayerMapclass GreeterMap extends LayerMap.Service<GreeterMap>()("GreeterMap", { // Define the lookup function for the layer map lookup: (name: string) => Layer.succeed(Greeter)({ greet: Effect.succeed(`Hello, ${name}!`) }),
// If a layer is not used for a certain amount of time, it can be removed idleTimeToLive: "5 seconds"}) {}
// Usageconst program = Effect.gen(function*() { // Access and use the Greeter service const greeter = yield* Greeter return yield* greeter.greet}).pipe( // Use the GreeterMap service to provide a variant of the Greeter service Effect.provide(GreeterMap.get("John"))).pipe( // Provide the GreeterMap layer Effect.provide(GreeterMap.layer))
await Effect.runPromise(program) // => "Hello, John!"Service class shape produced by LayerMap.Service.
When to use
Use as the public type for classes returned by LayerMap.Service when an API
needs to accept, return, or alias the generated service class and its static
helpers.
Details
It combines a Context.Service tag for the LayerMap with default layers
and helper accessors for retrieving, using, and invalidating keyed resources.
See
- Service for creating concrete
LayerMapservice classes
Signature
interface TagClass<in out Self, in out Id extends string, in out K, in out I, in out E, in out R, in out LE, in out Deps extends Layer.Layer<any, any, any>> extends ServiceClass<Self, Id, LayerMap<K, I, E>> { constructor(_: never); readonly contextEffect: (key: K) => Effect<Context<I>, E, Scope | Self>; readonly contextEffectOption: (key: K) => Effect<Option<Context<I>>, E, Scope | Self>; readonly get: (key: K) => Layer<I, E, Self>; readonly invalidate: (key: K) => Effect<void, never, Self>; readonly layer: Layer<Self, LE | Deps extends Layer<_A, _E, _R> ? _E : never, Exclude<R, Deps extends Layer<_A, _E, _R> ? _A : never> | Deps extends Layer<_A, _E, _R> ? _R : never>; readonly layerNoDeps: Layer<Self, LE, R>;}