@nestbolt/notifications
Introduction
Multi-channel notification system for NestJS -- send notifications via database, email, and custom channels with a clean, class-based API.
Overview
@nestbolt/notifications is a multi-channel notification system for NestJS applications. It provides a unified, class-based API for sending notifications through multiple delivery channels -- database, email, and any custom channel you define -- all from a single notification class.
The package draws inspiration from Laravel's notification system, adapted to fit naturally within the NestJS ecosystem using TypeORM, dependency injection, and decorators.
Key Features
- Multi-channel delivery -- Send a single notification through multiple channels (database, mail, Slack, SMS, webhooks, or anything else) by defining a
via()method on your notification class. - Database notifications -- Store notifications in a
notificationstable with full read/unread tracking, querying, and bulk operations out of the box. - Mail notifications -- Send rich HTML and plain-text emails using the fluent
MailMessagebuilder API, powered by nodemailer. - Custom channels -- Implement the
NotificationChannelinterface to deliver notifications via any transport: Slack, Twilio, Firebase, webhooks, or anything else. - Entity mixin -- Add
notify(),unreadNotifications(),markAllNotificationsAsRead(), and other convenience methods directly to your TypeORM entities with the@Notifiable()decorator andNotifiableMixin. - Lifecycle events -- Hook into
notification.sending,notification.sent,notification.failed,notification.read, andnotification.all-readevents using@nestjs/event-emitter. - Global module -- Register once with
forRoot()orforRootAsync()and useNotificationServiceanywhere in your application without re-importing. - TypeORM integration -- The database channel uses TypeORM repositories, supports multiple database drivers, and includes composite indexes for efficient querying.
Architecture
The notification system is built around a few core concepts:
Notification classes
Each notification is a plain TypeScript class that extends the Notification base class. It declares which channels to use via the via() method, and provides a toDatabase(), toMail(), or custom toX() method for each channel.
Channels
A channel is a delivery mechanism. The package ships with two built-in channels:
| Channel | Description |
|---|---|
database | Persists the notification payload to a notifications table via TypeORM. |
mail | Sends an email via nodemailer using the MailMessage builder. |
You can register any number of custom channels (Slack, SMS, push notifications, webhooks) by implementing the NotificationChannel interface.
The ChannelManager
The ChannelManager is an internal registry that maps channel names (strings like "database", "mail", "slack") to their corresponding NotificationChannel implementations. When a notification is sent, the NotificationService iterates over the channels returned by via(), resolves each one through the ChannelManager, and calls its send() method.
NotificationService
The NotificationService is the primary entry point. It handles:
- Sending notifications to one or many recipients
- Querying stored notifications from the database
- Read/unread tracking and bulk operations
- Emitting lifecycle events (when
@nestjs/event-emitteris installed)
Notifiable entities
Any TypeORM entity can become a notification recipient by applying the @Notifiable() decorator and extending NotifiableMixin(BaseEntity). This adds methods like notify(), getNotifications(), unreadNotifications(), and markAllNotificationsAsRead() directly to entity instances.
How It Works
The flow for sending a notification looks like this:
- You create a notification class (e.g.,
OrderShippedNotification) that extendsNotification. - The
via()method returns the list of channels:["database", "mail"]. - You call
notificationService.send(user, new OrderShippedNotification(order))oruser.notify(new OrderShippedNotification(order)). - For each channel in
via():- A
notification.sendingevent is emitted. - The
ChannelManagerresolves the channel by name. - The channel's
send()method is called with the notifiable entity and notification. - On success, a
notification.sentevent is emitted. - On failure, a
notification.failedevent is emitted and the error is re-thrown.
- A
Next Steps
- Installation -- Install the package and its dependencies.
- Quick Start -- Get up and running with a complete example.
- Configuration -- Learn about
forRoot()andforRootAsync()options. - Creating Notifications -- Build notification classes with the full API.