Large backends tend to grow in strata: configuration at the bottom, then infrastructure services (database, mail), business modules, and finally the transport layer (HTTP, RPC). Laminar makes those strata a first-class, typed concept.
Idea
What it means
Explicit factories
A component is created by a plain function you write and call order you control.
Typed boundaries
Each layer declares what it receives; PublicLayer<T> hides what must not leak.
Synchronous assembly
Building a container never awaits. Asynchronous work lives in lifecycle hooks.
No global state
Every call of a creator builds a fresh container; there is no singleton registry.
The two-phase model
Laminar separates building an object graph from starting it.
sequenceDiagram
participant App
participant Creator as createServices
participant Hooks as init / dispose
App->>Creator: createServices(config)
Note over Creator: synchronous, factories run in definition order
Creator-->>App: services container
App->>Hooks: await init(services)
Note over Hooks: async onInit hooks, depth-first
App->>Hooks: await dispose(services)
Note over Hooks: async onDispose hooks, reverse order
Introduction
Why Laminar
Large backends tend to grow in strata: configuration at the bottom, then infrastructure services (database, mail), business modules, and finally the transport layer (HTTP, RPC). Laminar makes those strata a first-class, typed concept.
PublicLayer<T>hides what must not leak.The two-phase model
Laminar separates building an object graph from starting it.
await init(layer)).await dispose(layer)).Installation
The package is ESM-only and ships its own type declarations.