How Would You Design a Notification System?
Learn how to design a scalable notification system: event-driven fan-out, channel workers, preferences, dedup, and prioritization.
Expected Interview Answer
A notification system is designed as an event-driven pipeline where upstream services publish notification events to a queue, a set of channel-specific workers consume and format each event for push, email, or SMS, and a preference/dedup layer ensures the right user gets the right message on the right channel without being spammed by duplicates.
Upstream services (an order service, a chat service, and so on) never send notifications directly — they publish a notification event describing what happened onto a message queue or event bus, keeping notification concerns fully decoupled from business logic. A notification service consumes these events, checks the user's preferences (which channels they allow, quiet hours, opt-outs) and applies deduplication/rate limiting so the same event does not trigger five redundant alerts, then fans out the formatted message to channel-specific workers — one for push notifications (via APNs/FCM), one for email (via an SMTP/SES provider), one for SMS (via Twilio or similar). Each channel worker handles its own retry logic and provider-specific rate limits, and failures are tracked so a user is not silently dropped from receiving an important notification. For very high fan-out events (like a notification to millions of followers), the system batches and throttles delivery rather than pushing everything instantly, and often prioritizes by notification type (a security alert outranks a “someone liked your post” notification).
- Decoupling notification delivery from business logic via a queue keeps producers simple and fast
- Per-channel workers isolate provider-specific failures/rate limits so one channel outage does not block others
- A centralized preference/dedup layer prevents notification spam and respects user opt-outs consistently
- Batching and prioritization keep massive fan-out events from overwhelming providers or annoying users
AI Mentor Explanation
Designing a notification system is like a stadium's public address setup where the scoring team does not personally shout updates to every section — they log the event (a wicket, a boundary) with the PA operator, who checks which sections have their speakers on, dedupes repeated announcements of the same ball, and routes the message to the right speaker banks in each stand. If one speaker bank fails, the operator retries on that bank without silencing the others. For a match-defining event like a final wicket, the PA prioritizes that announcement over routine updates. That decoupled, channel-aware fan-out with prioritization is exactly how a notification system delivers events to users.
Step-by-Step Explanation
Step 1
Producer publishes a notification event
An upstream service (orders, chat, etc.) emits an event describing what happened onto a queue, decoupled from delivery concerns.
Step 2
Notification service applies preferences and dedup
The consumer checks the user's enabled channels, opt-outs, quiet hours, and rate limits before proceeding.
Step 3
Fan out to channel-specific workers
Separate workers handle push (APNs/FCM), email (SMTP/SES), and SMS (Twilio), each with its own retry logic and rate limits.
Step 4
Track delivery and retry on failure
Failed deliveries are retried per channel, and high-priority notifications (e.g., security alerts) are delivered ahead of low-priority ones.
What Interviewer Expects
- Decouples notification triggering from delivery via an event/queue-based architecture
- Separates channel-specific concerns (push/email/SMS) into isolated workers with their own retry logic
- Discusses user preferences, deduplication, and rate limiting as first-class concerns, not an afterthought
- Addresses massive fan-out scenarios with batching/throttling and priority ordering
Common Mistakes
- Having business services call notification providers directly instead of publishing events to a queue
- Ignoring deduplication, leading to users receiving multiple alerts for the same event
- Treating all channels as equally reliable and not isolating failures per channel
- Not considering priority — treating a security alert the same as a low-value social notification
Best Answer (HR Friendly)
“I would keep the parts of the app that trigger notifications — like an order status changing — completely separate from the part that actually sends them. The triggering service just publishes an event, and a dedicated notification service picks it up, checks what the user wants to be notified about and on which channel, and sends it out through push, email, or SMS, retrying only the channel that failed rather than the whole notification.”
Code Example
async function handleNotificationEvent(event) {
const prefs = await preferenceStore.get(event.userId)
if (await dedupStore.isDuplicate(event.eventId, event.userId)) {
return // already delivered recently, skip
}
const channels = prefs.enabledChannels.filter((c) => !prefs.quietHours.includes(c))
await Promise.allSettled(
channels.map((channel) => {
const worker = channelWorkers[channel] // push | email | sms
return worker.send({
userId: event.userId,
title: event.title,
body: event.body,
priority: event.priority, // e.g., 'high' for security alerts
})
})
)
await dedupStore.markDelivered(event.eventId, event.userId)
}Follow-up Questions
- How would you prevent a single event from triggering duplicate notifications across channels?
- How would you handle a viral event that needs to fan out to millions of users at once?
- How would you prioritize a critical security alert over routine engagement notifications?
- How would you design retry and dead-letter handling per delivery channel?
MCQ Practice
1. Why should upstream services publish events to a queue instead of calling notification providers directly?
Publishing events to a queue keeps producers simple and isolates notification delivery so it can scale, retry, and fail independently of business logic.
2. Why are channel-specific workers (push, email, SMS) typically separated?
Isolating channels means an outage or rate limit on, say, the SMS provider does not stall push or email delivery.
3. What is the purpose of deduplication in a notification system?
Deduplication ensures a user is not spammed with multiple alerts for the same underlying event, especially under retries or duplicate event publishing.
Flash Cards
Why publish notification events to a queue instead of calling providers directly? — To decouple business logic from delivery, letting the notification service scale and fail independently.
Why separate push/email/SMS into distinct workers? — So a failure or rate limit on one channel does not block delivery on the others.
What prevents duplicate alerts for the same event? — A deduplication layer that checks whether the event was already delivered to that user.
How should massive fan-out events be handled? — Batch and throttle delivery, and prioritize high-value notifications (e.g., security alerts) over routine ones.