Skip to main content

Layer Construction

Every zio-nats feature is a ZLayer. Knowing the dependency tree tells you which layers to pass to .provide and what each one requires - this page is a reference for wiring any combination of services together.

Dependency tree

All services depend, directly or indirectly, on Nats. NatsConfig is the single entry point:

NatsConfig
└── Nats.live
├── JetStream.live
├── JetStreamManagement.live
├── KeyValue.live(name)
├── KeyValueManagement.live
├── ObjectStore.live(name)
└── ObjectStoreManagement.live

NatsService is the exception - it is not a ZLayer. It is obtained via nats.service(config, endpoints), a scoped ZIO effect whose lifetime is tied to the enclosing Scope. See Service Framework.

Automatic construction

ZIO's .provide resolves the dependency tree automatically. List the layers your program needs and ZIO wires them together in the right order - you do not need to express the relationships between them manually:

import zio.*
import zio.nats.*

def program: ZIO[Nats & JetStream & JetStreamManagement, NatsError, Unit] =
ZIO.unit

val _ = program.provide(
Nats.default,
JetStream.live,
JetStreamManagement.live
)

This is the recommended form for most applications. The section below covers when you need the layer as a value instead.

Manual composition

When you need the composed layer as a value - most commonly with .provideShared in test suites to share a single container across all tests - use >+>. Each step receives the full union of everything to its left as its input:

import zio.*
import zio.nats.*

val appLayer =
ZLayer.succeed(NatsConfig.default) >>>
Nats.live >+>
JetStream.live >+>
JetStreamManagement.live

>+> is "provide and keep". The output of appLayer above is Nats & JetStream & JetStreamManagement and can be passed directly to .provideShared.

Nats construction options

Three ways to provide the root Nats layer, in order of convenience:

FormUse when
Nats.defaultLocal development; localhost:4222, no auth
ZLayer.succeed(NatsConfig(...)) >>> Nats.liveConfig constructed in code
NatsConfig.fromConfig >>> Nats.liveConfig loaded from environment variables or HOCON

See Configuration for auth, TLS, timeouts, and the full field list.

Named bucket services

KeyValue and ObjectStore each have two construction forms depending on how the bucket fits into the program:

FormTypeUse when
KeyValue.live("name")ZLayer[Nats, NatsError, KeyValue]Bucket is a fixed service in the application
KeyValue.bucket("name")ZIO[Nats, NatsError, KeyValue]Bucket is acquired inside a for-comprehension

The same pattern applies to ObjectStore.live("name") and ObjectStore.bucket("name").

Next steps