FacteurJS
Facteur is a notification library for Node.js that makes sending notifications across different channels simple and efficient. It's framework-agnostic, so you can use it with any Node.js application. Out of the box, it supports in-app notifications, web push, email, SMS, and chat platforms like Slack, Discord, and Teams.
Whether you need something basic or complex, Facteur has you covered:
- Want to send a quick Slack notification when someone signs up?
- Need to send notifications through different channels based on user preferences?
- Building complex notification flows with conditions, delays, and retries?
- Want that classic real-time notification bubble in your web app, with read/unread status?
Facteur handles all of this. From simple one-off notifications to sophisticated multi-channel workflows.
Here's what you get out of the box:
- 📱 Multiple notification channels: web push, email, SMS, and chat platforms
- 🔌 Tons of supported providers (and you can build custom ones too)
- ⚡ Real-time notifications via Server-Sent Events or WebSockets
- ⚙️ Automatic user preference management
- 🛣️ Auto-generated API routes for your app
- 🎨 Frontend SDK for easy integration
- 🎯 Unified API for creating messages
- 🏢 Multi-tenancy support
In-App
Kysely
Store notifications using Kysely query builder
Knex
Store notifications using Knex.js query builder
@adonisjs/mail
Send email notifications using AdonisJS Mail system
Realtime
Socket.IO
Real-time notifications using Socket.IO
Transmit
Real-time notifications using WebSocket connections
Chats
Slack
Send notifications to Slack channels or users
Discord
Send notifications to Discord servers and channels
Microsoft Teams
Send notifications to Microsoft Teams channels
SMS
Twilio
Send SMS notifications using Twilio messaging service
AWS SNS
Send SMS notifications using AWS SNS messaging service
Web Push
Expo Notifications
Push notifications for Expo and React Native apps
Web Push
Browser push notifications using VAPID protocol
Firebase Cloud Messaging
Firebase Cloud Messaging for mobile push notifications
Misc
Webhook
Send HTTP requests to custom webhook endpoints
Features
Let's dive into what makes Facteur useful:
Sending Notifications
Sending notifications with Facteur is straightforward:
export class UserRegisteredNotification extends Notification<User> {
static options = {
name: 'User Registered',
category: 'business',
deliverBy: {
slack: true,
email: true,
}
}
asSlackMessage({ notifiable }) {
return SlackMessage.create()
.setText(`A new user has registered: ${notifiable.name}`)
.setChannel('#general');
}
asEmailMessage({ notifiable }) {
return EmailMessage.create()
.setSubject('New User Registration')
.setBody(`A new user has registered: ${notifiable.name}`)
}
}
import facteur from './facteur.js'
await facteur.send({
notification: UserRegisteredNotification,
notifiable: user,
})
That's it. This notification gets sent through all the channels you specified in deliverBy (Slack and Email in this case).
In-App Notifications
We just saw how to send notifications to external services. Now let's look at in-app notifications, think Twitter or Facebook notifications that appear in real-time and get stored in your database with read/unread status.
Facteur handles this elegantly too.
You can combine the database channel with the transmit channel (SSE) to send real-time notifications to your app while storing them in the database:
export class UserMentionedNotification extends Notification<User> {
static options = {
name: 'User Mentioned',
category: 'social',
deliverBy: {
database: true,
transmit: true,
}
}
asDatabaseMessage({ notifiable }) {
return DatabaseMessage.create()
.setTitle(`You were mentioned by ${notifiable.name}`)
.setBody(`Check out the post where you were mentioned!`)
.setData({ postId: '12345' });
}
asTransmitMessage({ notifiable }) {
return TransmitMessage.create().setData({ type: 'user_mentioned' });
}
}
Send it the same way:
import facteur from './facteur.js'
await facteur.send({
notification: UserMentionedNotification,
notifiable: user,
})
After sending, the notification gets saved to your database and delivered in real-time via Server-Sent Events or WebSockets. Users can see it in your app and mark it as read.
User Preferences
Facteur automatically handles user notification preferences. Users can choose which channels they want to receive notifications through, and Facteur respects those choices.
For example, if a user wants email and Slack notifications but not SMS, Facteur will only send through their preferred channels.
Automatic API Routes
Facteur comes with ready-to-use API routes for managing user preferences, listing notifications, marking them as read, and more.
This means you can build your frontend faster without worrying about the backend plumbing.
Frontend SDK
To make frontend integration even easier, Facteur provides a type-safe frontend SDK that works with your API (which exposes Facteur's automatic routes). Just install the SDK and start making API calls:
import facteur from '@facteurjs/sdk'
const notifications = await facteur.notifications.list({
userId: '123',
tenantId: '456'
})
await facteur.notifications.markAsRead({ notificationId: '789' })
await facteur.preferences.update({
userId: '123',
preferences: { email: true, slack: false, sms: true }
})
React hooks
To make frontend integration even MORE easier, Facteur provides some React TanStack Query hooks.
import { useNotifications } from '@facteurjs/react'
const { data, isLoading } = useNotifications({ userId: '123' })
const { mutate } = useMarkNotificationAsRead()
// And more hooks for marking all as read, updating preferences, etc.
Adapter-based
Facteur is built on an adapter-based architecture for every part of the system. This means you can swap out components like the database adapter ( Knex, Kysely, Prisma ...), notification channels ( Socket.io ? SSE ? Pusher ? ), or event the HTTP Framework ( Hono, Express, Fastify ... ). Everything is supported! Doesn't means everything is implemented but you can really easily write your own adapters when needed.
There's plenty more to explore, we'll cover it all in the following sections.
What's Coming
Facteur is actively being developed. Here's what's on the roadmap:
- Notification queuing support
- Debouncing and batching system
- Diagnostic channels for tracing and monitoring
- Topics.
- Headless React/Vue components for even easier integration ( Shadcn registry ? )
- Even more notification channels !
If you're interested in a specific feature, feel free to open an issue on GitHub or contribute to the project.
Our goal is to make Facteur the go-to notification solution for the Node.js ecosystem, a central hub for every notification channel you can think of. We need your help to make that happen!
Sponsor
If you like this project, please consider supporting it by sponsoring it. It helps a lot with maintenance and improvements. Thanks!