Novu now supports full multi-tenancy using Contexts, making it possible to isolate notifications, preferences, and credentials across tenants, workspaces, or applications within a single project.
All generated messages are tagged with the tenant:org-acme key.
You can later query or filter by this key using the API.
GET /v2/notifications?contextKey=tenant:org-acme
Within templates or layouts, context.tenant.data can be used for branding or logic:
{{context.tenant.data.name}} has a new billing update.
Supported use cases
Per-tenant isolation for notifications
Tenant-level credentials for chat integrations (e.g., Teams, Slack)
Dynamic content and branding driven by context data
Workspace or app-level scoping within shared environments
Real-world examples
A SaaS platform with multiple customer organizations sending workspace-specific updates.
An enterprise product using chat integrations where each workspace manages its own credentials.
An application separating preferences across multiple apps or environments under one Novu project.
Multi-tenancy in Novu introduces a consistent and reliable way to manage notification boundaries across tenants, workspaces, or applications, without duplicating workflows or environments.
Contexts make it simple to design systems where every notification and credential is tied to the right scope, predictable, queryable, and isolated by design.
Define tenant, app, or workspace context once, and Novu automatically scopes every notification, Inbox feed, preference, and delivery path to that context. No duplicated workflows, no custom filters, and no risk of cross-tenant leaks.
This feature is currently in beta. If you'd like to access Contexts, please email our support team at [email protected]
A Context in Novu is a structured object that describes the environment or scope to which a notification belongs. Instead of embedding metadata (like tenant ID or app name) into every trigger payload, you can now store it once and reference it everywhere.
When defining contexts, Novu supports multiple formats per key-value pair, allowing you to store and reference metadata relevant to your workflows and templates.
await novu.trigger('welcome-email', { to: 'user123', payload: { userName: 'John' }, context: { // Simple string format tenant: 'acme-corp', // Rich object format (ID only) app: { id: 'jira' }, // Rich object format (ID + data) region: { id: 'us-east', data: { name: 'US East', timezone: 'America/New_York', currency: 'USD' } } }});
As products mature, they typically shift from serving a single user group to supporting multiple groups.
Each organization, environment, or workspace has its own unique data, brand, and set of rules.
Most notification systems regard users as a single group with the same feeds, which leads teams to create weak filters and have duplicate subscribers across different tenants.
This is where <Inbox /> with Contexts excels for managing multi-tenancy. It offers built-in support directly at the notification layer, providing each tenant with a dedicated Inbox setup. This approach keeps your subscriber model and workflows intact without requiring any duplication.
Inbox Scoped by Context
When you render the Inbox, merely pass the same context:
The <Inbox /> knows precisely which messages to load, filtered by context.
Subscribers can switch between tenants or workspaces. Each one shows its own separate feed and settings.
Inbox A → tenant:org-acme
Inbox B → tenant:org-globex
Inbox C → tenant:org-novu
Each has its own unread counts, archived messages, and rules. They all use a single subscriber ID (user-123).
feat(dashboard,api-service, worker): include inbox unread count in the FCM and Expo messages available on the app badge
feat(worker): device token invalidation logic for FCM and Expo is now enabled, in active tokens will be removed and notified via the message.failed webhook
Fixes (4)
fix(api-service,application-generic): Passing null values when updating subscriber will now properly recognize and persist them
fix(api-service): translation keys escaping bug caused \"\ fields when used escaped fields in the i18n files
fix(js): notification count display for 99+ was properly fixed, where previously 100 was shown.