Typed notifications for Node.js and Bun
Define one Catalog, send typed notifications across email, WhatsApp, SMS, Telegram, Slack, and Discord. Pick your transport: SMTP, Resend, Cloudflare, or your own.
npx create-better-notify@latestScaffolds a new project with routing, transports, and templates.
import { createNotify, createClient } from '@betternotify/core'; import { emailChannel } from '@betternotify/email'; import { smtpTransport } from '@betternotify/smtp'; const notify = createNotify({ channels: { email: emailChannel() } }); const catalog = notify.catalog({ welcome: notify.email() .input(z.object({ name: z.string() })) .subject(({ input }) => `Welcome, ${input.name}`) .template(WelcomeEmail) }); const client = createClient({ catalog, transportsByChannel: { email: smtpTransport({ host: '...' }) } }); // fully typed: TS knows welcome expects { name: string } await client.welcome.send({ to: 'ada@example.com', input: { name: 'Ada' } });
Works with
Why Better-Notify
A library, not a platform.
No dashboard, no SaaS, no vendor lock-in. Define notifications in code and let the type system catch the rest.
End-to-end typed
One catalog types your sending across every channel. Refactor a route and every call site updates.
Channel-agnostic
Email, SMS, push, or your own channel. Same pipeline, different transport.
Composable middleware
Rate limit, retry, dedupe, log. Wrap any send with the same primitives.
Provider failover
multiTransport tries Resend, then Cloudflare, then SMTP. Health-checked, retry-aware.
Schema-first inputs
Zod, Valibot, or any Standard Schema. Validated before any side effect.
Plays well with everything
Express, Hono, tRPC, queue workers. ESM-only, Node 22+ & Bun, zero opinions.
Channels
Same API. Any channel.
Each channel is a package with its own rendering and transport. Swap providers without touching route definitions. Build your own with defineChannel() when the built-ins don't fit.
@betternotify/emailTyped templates with React Email, MJML, or plain functions. Multi-provider failover out of the box.
Resend · Cloudflare · SMTP · Mailchimp · React Email
@betternotify/whatsappSend text, media, templates, and interactive messages through Meta Cloud API. Same builder and pipeline as every other channel.
Meta Cloud API · Text · Media · Templates · Interactive
SMS
@betternotify/smsTwilio
Push
@betternotify/pushAPNs · FCM · Web Push
Telegram
@betternotify/telegramBot API · Text · Photos · Documents
Discord
@betternotify/discordWebhook API · Embeds · Username override
Slack
@betternotify/slackBot API · Block Kit · Threads
Zapier
@betternotify/zapierWebhooks · Automations · 7000+ apps
Custom
defineChannel()Webhooks · in-app
The pipeline
One flow. Every channel.
Every send goes through the same five phases: input validation, render, middleware, transport, result. Hooks observe; middleware controls.
mail.welcome.send()→SMTP · GmailObserve without altering the send. onBeforeSend, onExecute, onAfterSend, onError.
Wrap, gate, retry, mutate. If removing it would change whether a message goes out, it's middleware, not a hook.
Pluggable per-channel. multiTransport composes failover, round-robin, race, parallel, mirrored.
AI-native
Your catalog is their toolbox.
Expose your notification routes as MCP tools. Claude, Cursor, Copilot — any agent that speaks the Model Context Protocol can discover and send notifications through your typed catalog.
// your catalog — same as always const catalog = rpc.catalog(({ transactional: rpc.catalog(({ welcome: rpc .email() .input(z.object(({ name: z.string() })) .subject('Welcome!') .template(WelcomeEmail), }), });
transactional.welcome.sendSend email notification via welcome
transactional.welcome.renderPreview email notification for welcome without sending
notifications://recentnotifications://statsZero config discovery
Each catalog route becomes a typed tool. Input schemas, descriptions, and validation — automatic.
Same pipeline, new caller
Middleware, hooks, failover — all active. Agent sends go through the exact same execution path.
stdio or HTTP
Run locally as a subprocess or deploy as a network service with bearer auth and streaming.
Comparison
When to reach for it.
Better-Notify sits between cloud notification platforms like Novu, Knock, and Courier — and a hand-rolled sendEmail() helper.
| Cloud platformsNovu · Knock · Courier | Hand-rolled | Better-Notify | |
|---|---|---|---|
| Lives in your codebase | — dashboard | ✓ | ✓ |
| End-to-end typed call sites | — stringly-typed | partial | ✓ catalog → sender |
| Multi-provider failover | ✓ vendor-locked | — DIY | ✓ multiTransport() |
| Multi-channel from one route | varies | — DIY | ✓ shared pipeline |
| Validation before side effects | partial | — DIY | ✓ Standard Schema |
| Vendor lock-in | high | none | none |
| Pricing model | per-send | free | free · MIT |
Quick start
Install. Define. Send.
Three packages, three minutes. Email, SMS, Telegram, Slack, and Discord channels ship today.
Bootstrap your project
npx create-better-notify@latestScaffolds a new project with routing, transports, and templates.
Install
Define your catalog
const welcome = rpc.email() .input(WelcomeSchema) .subject(({ n }) => `Hi, ${n}`) .template(WelcomeAdapter);
Send anywhere
await mail.welcome.send({ to: 'ada@example.com', input: { name: 'Ada' }, });
Open Source
Notifications, from your code.
Read the docs, follow the quickstart, ship a typed sender by lunch. MIT licensed; no signup; no dashboard.
Latest from the blog
View allHow to Send Email in Node.js with SMTP
Send emails from Node.js using SMTP with typed routes, validated inputs, and middleware. A step-by-step guide using Better-Notify.
5 New Transports, 2 Channels, Bun Support, and More
Announcing Web Push, GitHub notifications, Autosend, Selligent, and OneSignal transports — plus Bun runtime support and catalog channel inference.
Introducing Better-Notify
Type-safe notification infrastructure for Node.js — email, SMS, push, and custom channels from one typed catalog.

Crafted by
Lucas Reis
A Brazilian full-stack software engineer focused on developer experience and software quality.
Shoutouts, partnerships, or coffee chats: reis@better-notify.com
Better-Notify
Typed notifications for Node.js & Bun. Open source, MIT licensed.