End-to-end typed notification infrastructure for Node.js and Bun.
Website · Docs · Blog · Changelog
- Typed end-to-end — one catalog type drives the client, queue worker, and webhook router. Schema and template can't silently drift.
- Multi-channel — email, SMS, push, Slack, Discord, Telegram, and more from the same pipeline. Define once, send anywhere.
- Zero lock-in — swap transports (SMTP, Resend, Mailchimp, Cloudflare Email) without touching business logic. Standard Schema means no hard Zod dependency either.
- Batteries included — middleware (rate-limit, idempotency, tracing, dry-run), hooks, plugins, and a logger built into core.
npm install @betternotify/core @betternotify/email zodimport { createNotify, createClient } from '@betternotify/core';
import { emailChannel, mockTransport } from '@betternotify/email';
import { z } from 'zod';
const email = emailChannel({ defaults: { from: 'hello@example.com' } });
const rpc = createNotify({ channels: { email } });
const catalog = rpc.catalog({
welcome: rpc
.email()
.input(z.object({ name: z.string() }))
.subject(({ input }) => `Welcome, ${input.name}`)
.template({ render: async ({ input }) => ({ html: `<h1>Hi ${input.name}</h1>` }) }),
});
const mail = createClient({
catalog,
transportsByChannel: { email: mockTransport() },
});
await mail.welcome.send({ to: 'john@example.com', input: { name: 'John' } });Core: @betternotify/core · Integrations: @betternotify/mcp
Scaffolding: create-better-notify
npx create-better-notify@latestCreated by Lucas Reis · X
MIT License