Message Broker
Call procedures across services via NATS, Redis, or any message broker.
Normally Silgi talks over HTTP. But sometimes your services need to talk to each other through a message broker like NATS or Redis. The broker adapter lets you do exactly that — same router, same client, just a different transport underneath.
How it works
You pick a driver for your broker. The driver handles the messaging — Silgi handles everything else (routing, validation, errors, types).
Every driver has two sides:
- Server listens for requests and sends back results
- Client sends requests and waits for results
The API is the same regardless of which broker you use.
NATS
NATS is the easiest option — it has built-in request-reply, so everything just works.
bash pnpm add silgi nats bash npm install silgi nats bash bun add silgi nats Connect to NATS and create a driver
import { } from 'nats'
import { } from 'silgi/broker/nats'
const = await ({ : 'localhost:4222' })
const = ()Start the server
Pass your router and the driver. This is identical to how you'd use handler() — just over NATS instead of HTTP.
import { } from 'silgi/broker'
import { } from './router'
await (, driver, {
: () => ({ : getDB() }),
})Call from the client
The client works exactly like the HTTP client. Same types, same autocomplete.
import { } from 'silgi/broker'
import { } from 'silgi/client'
import type { } from './router'
const = <>(new (driver))
const = await .users.list({ : 10 })Scaling with queue groups
If you run multiple server instances, pass queue so each request goes to only one of them:
import { } from 'silgi/broker/nats'
// all instances use the same group name — NATS load-balances automatically
const = (nc, { : 'api-workers' })Redis
Redis works too, but it doesn't have built-in request-reply like NATS. The driver simulates it using temporary channels — you don't need to worry about the details.
bash pnpm add silgi ioredis bash npm install silgi ioredis bash bun add silgi ioredis Redis needs two connections — one for publishing, one for subscribing. This is a Redis limitation, not a Silgi one.
Create the driver
import from 'ioredis'
import { , } from 'silgi/broker/redis'
const = new ()
const = ((, .()))Start the server
import { } from 'silgi/broker'
import { } from './router'
await (, driver, {
: () => ({ : getDB() }),
})Call from the client
import { } from 'silgi/broker'
import { } from 'silgi/client'
import type { } from './router'
const = <>(new (driver))
const = await .users.list({ : 10 })Using a different broker
If you use RabbitMQ, MQTT, or something else, you can write your own driver. It's just two functions:
import type { BrokerDriver } from 'silgi/broker'
function (: ): BrokerDriver {
return {
// Server side: listen for requests, call reply() with the result
(, ) {
const = .subscribe(, () => {
(.payload, () => .send(.replyTo, ))
})
return () => .unsubscribe()
},
// Client side: send a request, wait for the response
async (, , ) {
return .request(, , { : ?. })
},
}
}Testing
Use memoryBroker() in your tests — it works the same way but runs in-memory, no Docker needed:
import { , , } from 'silgi/broker'
import { } from 'silgi/client'
const = ()
await (appRouter, )
const = <>(new ())
// now test as usual
const = await .health()What's next?
- Client — client configuration
- Message Port — RPC over MessagePort (Electron, Web Workers)