Novu is not just “send an email from my app.”
It is communication infrastructure: workflows, providers, user preferences, Inbox, digests, push, SMS, chat channels, webhooks, real-time updates, and now agent communication patterns.
That makes it useful, but also heavier than a casual notification sidecar.
What is Novu?
Novu is an open-source communication infrastructure platform for products and agents.
The top-level promise is one API and one conversation model across channels:
- Inbox/In-App;
- Email;
- SMS;
- Push;
- Chat;
- Slack;
- Microsoft Teams;
- Telegram;
- WhatsApp;
- and more provider-backed surfaces.
I analyzed commit:
36c5c0cefa400e8edc6ec8b18ac4574288eabd03
The repository default branch is next. The community Docker Compose file I inspected pins Novu app images at:
3.19.0
Licensing Notes
Novu is a mixed-license monorepo.
The community code is covered by LICENSE-MIT, while enterprise package paths are covered by LICENSE-ENTERPRISE and EE-PACKAGES-LICENSE. GitHub reports the repo license as NOASSERTION, which is expected for this kind of layout.
So the short version is:
Community Novu: MIT licensed
Enterprise packages: proprietary license
That distinction is worth keeping in the post because it affects how teams evaluate self-hosting, redistribution, and commercial use.
Why Self-Host It?
Self-host Novu if your product has outgrown ad hoc notification code.
Good use cases:
- user notification feeds;
- transactional email orchestration;
- SMS and push delivery;
- chat channel delivery;
- Slack or Teams notifications;
- user notification preferences;
- notification workflows with branching and conditions;
- digesting many events into fewer messages;
- an embeddable Inbox component;
- agent-to-human communication across real channels.
Novu is not the email/SMS/push provider itself. It is the orchestration layer in front of those providers. You still bring provider accounts and credentials for SMTP, SES, Twilio, FCM, APNS, Slack, Teams, Telegram, and similar services.
Architecture
The community self-hosted stack has six main services:
- API: NestJS backend on port
3000. - Worker: background processor for notification workflow and delivery jobs.
- WebSocket: real-time service on port
3002. - Dashboard: Vite/React admin UI on port
4000. - MongoDB: persistent application data.
- Redis: queue/cache/broker dependency.
The repo also includes:
- provider integrations in
packages/providers; - React Inbox components in
packages/react; - JavaScript, Next.js, React Native, and stateless SDK packages;
- a framework package for workflows and bridge integrations;
- agent tooling and chat adapters;
- webhook and inbound-mail app services;
- shared DAL, notification, and application-generic libraries.
It is a real platform monorepo, not a single Express app.
The Dashboard
Novu’s Dashboard is a Vite/React application.
The Docker image builds static assets and serves them through http-server on port 4000. Runtime configuration is handled by the dashboard entrypoint: it scans all VITE_* environment variables and injects them into window._env_ in index.html.
That means you can configure these at runtime:
VITE_API_HOSTNAME=http://localhost:3000
VITE_WEBSOCKET_HOSTNAME=http://localhost:3002
I smoke-tested the dashboard image directly and confirmed:
/returned HTTP200;- the title was
Novu Cloud Dashboard; VITE_API_HOSTNAMEwas injected into the HTML.
Self-Hosting with Docker
The reusable Home-Lab compose file is based on Novu’s community Docker Compose, with public ports bound to loopback by default and secrets required through .env.
Pre-Requisites - Docker
Install Docker on your system before proceeding:
- Linux: Official Docker Engine install guide
- Windows / Mac: Docker Desktop
Verify installation: docker --version && docker compose version
The reusable Home-Lab compose file is here:
The site can include the same snippet from the Home-Lab submodule:
assets/snippets/novu/docker-compose.yml
Create the environment file:
cd assets/snippets/novu
cp .env.sample .env
Generate secrets:
openssl rand -hex 32
openssl rand -hex 16
Use the 64-character secret output for:
JWT_SECRET
NOVU_SECRET_KEY
Use the 32-character output for:
STORE_ENCRYPTION_KEY
That key is important because Novu uses it to encrypt provider credentials.
Start the stack:
docker compose up -d
Then open:
http://localhost:4000 Dashboard
http://localhost:3000 API
http://localhost:3002 WebSocket service
Reverse Proxy Notes
For real use, put Novu behind HTTPS.
The important part is keeping browser-facing and internal URLs straight:
VITE_API_HOSTNAMEis used by the dashboard in the browser.VITE_WEBSOCKET_HOSTNAMEis used by the dashboard in the browser.API_ROOT_URLis the externally meaningful API URL.- Worker-to-API traffic should use the internal Docker service URL, not the public URL.
FRONT_BASE_URLshould point at the dashboard URL.
For a subdomain setup, you might end up with:
FRONT_BASE_URL=https://novu.example.com
API_ROOT_URL=https://novu-api.example.com
VITE_API_HOSTNAME=https://novu-api.example.com
VITE_WEBSOCKET_HOSTNAME=https://novu-ws.example.com
Exact proxy routing depends on whether you split API, dashboard, and WebSocket traffic by subdomain or by path.
Field Test
I validated the published images and compose path in a bounded way.
Image manifests for:
ghcr.io/novuhq/novu/api:3.19.0;ghcr.io/novuhq/novu/worker:3.19.0;ghcr.io/novuhq/novu/ws:3.19.0;ghcr.io/novuhq/novu/dashboard:3.19.0.
Each provided Linux amd64 and arm64 images.
The reusable Compose file validated with:
JWT_SECRET=1111111111111111111111111111111111111111111111111111111111111111 \
STORE_ENCRYPTION_KEY=11111111111111111111111111111111 \
NOVU_SECRET_KEY=2222222222222222222222222222222222222222222222222222222222222222 \
MONGO_INITDB_ROOT_USERNAME=novu \
MONGO_INITDB_ROOT_PASSWORD=replace-me \
docker compose -f assets/snippets/novu/docker-compose.yml config
I also attempted a full stack startup on alternate ports because port 3000 was already in use on this host. The images pulled, but Docker failed before container health checks because the daemon could not allocate another bridge network:
all predefined address pools have been fully subnetted
That is a host-level Docker network exhaustion issue, not a Novu application error.
To still verify the UI image, I ran the dashboard directly:
docker run -d --name novu-dashboard-foss-trial \
-e VITE_API_HOSTNAME=http://127.0.0.1:13000 \
-e VITE_WEBSOCKET_HOSTNAME=http://127.0.0.1:13002 \
-p 127.0.0.1:14000:4000 \
ghcr.io/novuhq/novu/dashboard:3.19.0
Result:
- HTTP
200from/; - title
Novu Cloud Dashboard; - runtime
VITE_API_HOSTNAMEinjection confirmed.
Operational Caveats
Novu is application infrastructure. Do not treat it like a small hobby widget if it is responsible for production customer messages.
Watch these areas:
- MongoDB backups;
- Redis behavior and queue expectations;
- secret generation and secret rotation;
- stable
STORE_ENCRYPTION_KEY; - provider credentials;
- API and WS public exposure;
- rate limiting;
- HTTPS;
- outbound mail/SMS/push provider quotas;
- deliverability and retry behavior.
Self-hosting gives control, but it does not remove the hard parts of notifications: deliverability, provider quirks, user preferences, retries, and observability.
FAQ
Is there a UI?
Yes. The Dashboard runs on port 4000 and is a Vite/React app served from a Docker image.
Can the dashboard be deployed statically?
Mostly yes as a static Vite asset bundle, but it is not useful by itself. Full functionality requires the API, WebSocket service, MongoDB, Redis, and correctly configured runtime URLs.
Is Novu only for email?
No. Email is one channel. Novu also covers Inbox/In-App, SMS, Push, Chat, Slack, Teams, Telegram, WhatsApp, and other provider-backed channels.
Does self-hosting include free SMS or email sending?
No. Novu orchestrates providers. You still need provider accounts and credentials.
Is it open source?
The community code is MIT-licensed, while enterprise package paths are proprietary. Treat the repo as mixed-license.
Can agents use it?
Yes. The current README explicitly positions Novu for agent communication infrastructure as well as product notifications. The repo includes agent toolkit, event protocol, framework, and chat adapter packages.
Can I run it on ARM?
The checked 3.19.0 app images expose linux/arm64 manifests. The full stack still needs enough memory and disk for Node services, MongoDB, Redis, and the dashboard.
Conclusion
Novu is compelling when notifications have become product infrastructure rather than a few mailer calls.
It gives you a dashboard, workflow model, provider abstraction, embeddable Inbox, real-time service, background workers, SDKs, and agent communication building blocks.
The tradeoff is complexity. The self-hosted stack is absolutely runnable, but it is a multi-service platform. Generate real secrets, put it behind HTTPS, back up MongoDB, keep STORE_ENCRYPTION_KEY safe, and test the channels you actually depend on.
Comments