Silgi

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).

client.users.list() deliver request { users: [...] } deliver response Service A (client) NATS / Redis Service B (server)

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)

On this page