On this pageFunctions
ManagedResource
Creates type-safe managed resource configurations from a dependency schema.
Use this when a resource is expensive or stateful and should only exist while
the model is in a particular state — a camera stream during a video call, a
WebSocket connection while on a chat page, or a Web Worker pool during a
computation. For resources that live for the entire application lifetime, use
the static resources config instead.
**Lifecycle** — The runtime watches each config's modelToMaybeRequirements
after every model update, structurally comparing the result against the
previous value:
- Option.none() → Option.some(params): calls acquire(params), then
dispatches onAcquired(value).
- Option.some(paramsA) → Option.some(paramsB) (structurally different):
releases the old resource, then acquires a new one with paramsB.
- Option.some(params) → Option.none(): calls release(value), then
dispatches onReleased(). No re-acquisition occurs.
If acquire fails, onAcquireError is dispatched and the resource daemon
continues watching for the next deps change — a failed acquisition does not
crash the application.
**Config fields:**
- resource — The identity tag created with ManagedResource.tag. Appears
in the Effect R channel so commands that call .get are type-checked.
- modelToMaybeRequirements — Extracts requirements from the model.
Option.none() means "release", Option.some(params) means
"acquire/re-acquire if params changed". For resources with no
parameters, use S.Option(S.Null) and return Option.some(null) —
not S.Struct({}), which has no fields for equivalence comparison.
- acquire — Creates the resource from the unwrapped params. The returned
Effect should fail when acquisition fails — errors in the error channel
flow to onAcquireError as a message instead of crashing the runtime.
- release — Tears down the resource. Errors thrown here are silently
swallowed — release must not block cleanup.
- onAcquired — Message dispatched when acquire succeeds.
- onAcquireError — Message dispatched when acquire fails.
- onReleased — Message dispatched after release completes.
Creates a managed resource identity with a .get accessor for use in commands.
<Value>(): (key: Key) => ManagedResource<Value, ManagedResourceService<Key>>Internal configuration for a single managed resource, used by the runtime.
type ManagedResourceConfig = {
acquire: (params: unknown) => Effect.Effect<unknown, unknown>
modelToMaybeRequirements: (model: Model) => unknown
onAcquired: (value: unknown) => Message
onAcquireError: (error: unknown) => Message
onReleased: () => Message
release: (value: unknown) => Effect.Effect<void>
resource: ManagedResource<any>
schema: Schema.Schema<any>
}Type-level utility to extract the service union from a ManagedResources type.
type ManagedResourceServicesOf = MR extends ManagedResources<any, any, infer S>
? S
: neverA record of named managed resource configurations, keyed by dependency field name.
type ManagedResources = Record<string, ManagedResourceConfig<Model, Message>> & {
[ManagedResourceServicesPhantom]: Services
}Type-level utility to extract the service identity type from a ManagedResource.
type ServiceOf = T extends ManagedResource<any, infer S>
? S
: neverType-level utility to extract the value type from a ManagedResource.
type Value = T extends ManagedResource<infer V, any>
? V
: neverA model-driven resource with acquire/release lifecycle. Access the resource
value in commands via .get, which fails with ResourceNotAvailable when
the resource is not currently active. The service identity appears in the
Effect R channel, providing compile-time enforcement that the resource is
registered.
interface ManagedResource {
[ManagedResourceTypeId]: typeof ManagedResourceTypeId
get: Effect<Value, ResourceNotAvailable, Service>
key: string
}