Introduction

FacteurJS

Facteur is a framework-agnostic notification library for Node.js. Define one notification class, format messages for each channel, and send to a recipient or a list of recipients.

Current channels include database storage (Knex/Kysely), AdonisJS Mail, Twilio SMS, AWS SNS SMS, Web Push, Firebase Cloud Messaging, Expo, Slack/Discord webhooks, Socket.IO and Transmit (SSE). WhatsApp is planned, not implemented.

In-App

Kysely

Store notifications using Kysely query builder

Knex

Store notifications using Knex.js query builder

Mail

@adonisjs/mail

Send email notifications using AdonisJS Mail system

Realtime

Socket.IO

Real-time notifications using Socket.IO

Transmit

Real-time notifications using Server-Sent Events

Chats

Slack

Send notifications to Slack channels or users

Discord

Send notifications to Discord servers and 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

Sending notifications

After configuring Facteur, define a notification:

import { Notification } from '@facteurjs/core/types'
import { SlackMessage } from '@facteurjs/core/channels/slack'
export default class UserRegisteredNotification extends Notification<User> {
static options = {
name: 'User Registered',
category: 'business',
deliverBy: { slack: true },
}
asSlackMessage() {
return SlackMessage.create().setText(`A new user registered: ${this.notifiable.name}`)
}
}

User is your application's recipient model. It provides notificationTargets() with a Slack webhook destination (see Slack).

await facteur.notification(UserRegisteredNotification).to(user).send()

Use the fluent builder for explicit targets, parameters, tenants, retries and bulk sending. FCM and Expo support native batches when you opt in with .useDriverBatching().

In-app notifications

Combine database storage with a realtime channel to build a notification center. Store arbitrary JSON with DatabaseMessage.create().setContent(...); send realtime data with SocketIoMessage.create().setData(...) or TransmitMessage.create().setContent(...).

Facteur provides a Server API to list notifications, mark them read/seen and manage preferences. Register it through Hono, AdonisJS, or a custom HTTP adapter. Authorization is required, and the current mark-as route additionally needs an application-level ownership check.

Follow In-App Notifications for a complete setup.

Preferences and tenants

Database-backed User Preferences expose global, per-notification and tenant-specific channel settings. Category updates apply to the currently discovered classes in that category. Critical notifications bypass preferences; explicit via() also bypasses them. See that guide for current resolution limitations.

Use .tenant(id) to attach tenant context to a send. Multi-tenancy explains storage, API filtering and tenant-access requirements.

Frontend SDK and React hooks

The framework-independent client lives in @facteurjs/client:

import { createFacteurClient } from '@facteurjs/client'
const client = createFacteurClient({
apiUrl: 'https://api.example.com',
notifiableId: '123',
credentials: 'include',
})
const notifications = await client.notifications.list({ tenantId: '456' })
await client.notifications.markAsRead({ notificationId: '789' })
await client.preferences.update({ preferences: { slack: false } })

@facteurjs/react provides TanStack Query hooks inside FacteurProvider and QueryClientProvider:

import { useNotifications, useMarkAsRead } from '@facteurjs/react'
const { data, isLoading } = useNotifications({ tenantId: '456' })
const { mutate: markAsRead } = useMarkAsRead()

See Frontend SDK and React hooks. The hooks use HTTP; realtime subscriptions remain application code.

Extending Facteur

Create custom channels and HTTP adapters for services or frameworks not built in. Database adapters currently support Knex and Kysely; Prisma is not bundled.

Queues, delayed delivery, debouncing, topics and headless UI components are not implemented in the current sending API. Native FCM/Expo batching and retries are already available.

If you find Facteur useful, consider sponsoring the project.