Laravel Notifications, rebuilt for NestJS

One notification, every channel.

Write a notification once. Send it over mail, the database, a websocket, and Slack — synchronously, or queued through your own BullMQ. Type-safe payloads, on-demand routing, and a decoupled core where every channel and dispatcher is an opt-in package.

21 packages on npm · one notification, many channels · multi-tenant · sync or queued

notifications · fan-outdelivering

One call

await notifications.send(
  user,
  new InvoicePaid(invoice),
);

channel decorators infer the routes.
each channel reads its own payload.

Four channels

isolated · per-channel
mailada@example.com · "Invoice INV-1 paid"sent
databaseUser#42 · stored for in-app feedsaved
broadcastroom user:42 · realtime pushlive
slack#billing · Block Kit messagesent

Everything a notification layer needs

Define once, deliver everywhere. Pick your channels, pick your dispatcher, and let the core wire them together.

Channels, decoupled

Mail, database, broadcast and Slack — each an opt-in package. The core knows only an interface; channels are discovered from the Nest container, never hard-wired.

Sync or queued

Deliver inline by default, or set shouldQueue and route through an async dispatcher — in-process events, Redis, or the BullMQ you already run. Channels and dispatch are orthogonal.

Type-safe payloads

Each channel exports an interface your notification implements, so toMail, toDatabase and toSlack are checked at compile time. Forget one and TypeScript tells you.

On-demand routing

No entity? Send straight to an address — notifications.route("mail", "ops@x.com").notify(...). Chain extra routes for one-off, multi-channel blasts.

Bring your ORM

The database channel persists through a NotificationStore interface. Ship with the in-memory store, or plug the TypeORM or MikroORM adapter — write your own in a few methods.

Faithful to Laravel

send, via, toMail, sendNow, queued notifications, on-demand routing. If you know Laravel notifications, you already know this API.

Observable

Lifecycle events for every send, plus a first-class nestjs-telescope watcher that records each delivery — channel, recipient, payload, failure reason — in the dashboard.

Resilient by default

One channel failing never blocks the others. Choose continue-on-error or fail-fast; failures surface as events so you can alert, retry or log.

Built to test

A NotificationFake swaps the real service in tests, with Laravel-style assertions — assertSentTo, assertSentOnChannel, assertNothingSent. No SMTP, no queue, no flake.

Wire it in

One class. That's the notification.

A notification is a plain class: annotate each payload method with the channel handle — @Mail(), @Database() — and the channels are inferred. No magic strings, no via() array to keep in sync. Register the channels once in your module, then send from anywhere.

Full setup guide
invoice-paid.notification.ts
@Notification()
class InvoicePaid {
@Mail()
toMail() {
return new MailMessage()
.subject('Invoice paid')
.line('Thanks for your payment.');
}
}

Stop wiring notifications by hand.

Define a notification once, pick your channels, and ship — sync today, queued tomorrow, without touching the call site.