NATS
NatsActor integrates with NATS — the lightweight pub/sub
broker. Core NATS is fire-and-forget without durability;
for durable streams, see the JetStream variant.
import { ActorSystem, Props, NatsActor } from 'actor-ts';
const nats = system.actorOf( Props.create(() => new NatsActor({ servers: ['nats://nats-1:4222', 'nats://nats-2:4222'], name: 'my-app', })), 'nats',);
// Subscribe (wildcards supported):nats.tell({ kind: 'subscribe-nats', subject: 'events.>', subscriber: eventHandler,});
// Publish:nats.tell({ kind: 'publish', subject: 'events.user.signup', payload: JSON.stringify(event),});Settings
Section titled “Settings”interface NatsActorSettings extends BrokerCommonSettings { servers: string[] | string; name?: string; // client identifier user?: string; pass?: string; token?: string; tls?: TlsOptions; pingInterval?: number; // default 120s}Subjects (NATS topics)
Section titled “Subjects (NATS topics)”NATS uses .-delimited subjects:
events.user.signupevents.user.deleteorders.priority.placedmetrics.gauge.cpuSubjects are case-sensitive; per convention they’re lowercase + dot-separated.
Wildcards
Section titled “Wildcards”| Wildcard | Matches |
|---|---|
* | Exactly one token (matches user in events.user.signup). |
> | One or more tokens (matches user.signup in events.user.signup). |
'events.>' → events.user.signup, events.user.delete, events.order.placed'events.*.signup' → events.user.signup, events.admin.signup> can only appear as the last token.
Request / reply
Section titled “Request / reply”NATS supports synchronous request-reply natively:
nats.tell({ kind: 'request', subject: 'account.balance', payload: JSON.stringify({ accountId: '42' }), timeoutMs: 1_000, replyTo: this.self, // gets the reply message});
// Reply handler:override onReceive(msg: NatsRequestReply): void { if (msg.kind === 'reply') this.handleBalance(JSON.parse(...)); if (msg.kind === 'timeout') this.handleTimeout();}This is fast — a few hundred microseconds round-trip on localhost. Used widely as the “RPC over NATS” pattern.
When to use NATS
Section titled “When to use NATS”Three primary use cases:
- High-throughput pub/sub without the operational complexity of Kafka.
- Microservices request/reply — synchronous calls between services via subjects.
- Lightweight event distribution — fire-and-forget notifications, metrics, log streams.
For durable streams (replay, history, ack semantics), see JetStream below. For cluster-internal pub/sub, DistributedPubSub is simpler.
JetStream
Section titled “JetStream”For NATS with durability, use JetStreamActor:
import { JetStreamActor } from 'actor-ts';
const js = system.actorOf( Props.create(() => new JetStreamActor({ servers: ['nats://nats-1:4222'], streams: [ { name: 'ORDERS', subjects: ['orders.>'], storage: 'file', maxAge: 86_400 * 7, // 7 days retention }, ], })), 'js',);JetStream layers:
- Stream — durable log, subjects → records.
- Consumer — read cursor; multiple consumers can read the same stream independently.
- Ack semantics — like AMQP, consumers ack each message.
Use JetStream when you need:
- Replay — consumers can rewind to any offset.
- Persistence — survives broker restart (file-backed storage).
- Ordered consumption per subject.
Kafka still beats JetStream for massive scale (billions of events / sec across hundreds of partitions). JetStream is the sweet spot for “less than Kafka, more than core NATS.”
Peer dependency
Section titled “Peer dependency”npm install nats# or: bun add natsThe nats package includes both core NATS and JetStream clients.
Where to next
Section titled “Where to next”- I/O overview — the bigger picture.
- BrokerActor base — the shared lifecycle.
- Kafka — heavier durable streaming.
- MQTT — IoT-focused alternative.
- DistributedPubSub — for in-cluster pub/sub.