Live Notification System
Part of the Backend Developer Roadmap
In short
"Your order is out for delivery" popping up the second it happens feels magical. Behind it is an event, a saved notification and a push down an open connection.
A service that pushes real-time notifications to connected clients when events happen elsewhere in your system — practice for pub/sub and connecting real-time infra to your broader backend.

Think of it like this
The railway platform announcement
The station doesn't phone each passenger. When a train is late, the announcer rings the bell and speaks once, and everyone on that platform hears it. Passengers who arrive later check the display board. Live push for those online, saved list for the rest.
Watch it happen
From order shipped to a red badge
order.shipped #42
1/5The order service emits an event. It doesn't care how the user gets told.
The big ideas
What you need to know
Store, then push
The database is the truth; the live push is a bonus. Users who were offline still see everything later.
SSE is often enough
Notifications flow one way, server to user. Server-Sent Events are simpler than WebSockets for this.
Read state
Track read_at per notification, and add a mark-all-read endpoint. Badges must match what's actually unread.
Respect preferences
Let users mute types of notifications. Check preferences in the notifier, not in every service that emits events.
See it in code
Walk through the code
1import type { Response } from "express";2const streams = new Map<string, Set<Response>>();3 4app.get("/notifications/stream", requireLogin, (req, res) => {5 res.set({ "Content-Type": "text/event-stream", "Cache-Control": "no-cache" });6 res.flushHeaders();7 const set = streams.get(req.user.id) ?? new Set<Response>();8 set.add(res);9 streams.set(req.user.id, set);10 req.on("close", () => set.delete(res));11});12 13export async function notify(userId: string, note: { title: string }) {14 const saved = await db.notification.create({ data: { userId, ...note } });15 for (const res of streams.get(userId) ?? []) res.write(`data: ${JSON.stringify(saved)}\n\n`);16}1/3A logged-in user opens an event stream that stays open.
One user can have several tabs or devices open, so each user id maps to a set of streams. With more than one server, fan out through Redis Pub/Sub.
Save yourself the pain
Common mistakes
Oops
Only pushing live, never saving.
Do this instead
Offline users would miss everything. Save every notification and push as an extra.
Oops
Every service writing directly to user sockets.
Do this instead
Services emit events. One notifier decides who gets what, how, and respects mute settings.
Your mission
Milestone 1: a working bell icon
Quick check
A user was offline when their order shipped. How should they see the notification when they come back?
Go deeper
- 1Trigger a notification via pub/sub when an event occurs, e.g. a new comment.
- 2Handle users who are offline — queue or store notifications for when they reconnect.
- 3Support multiple notification types with different payloads on one connection.
More projects at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.