Build Real-Time Notifications in Next.js with Redis Pub/Sub
There's something magical about real-time notifications. A message appears, a badge updates, a toast pops up—and it all happens instantly. No refresh needed.
Most tutorials will tell you to set up WebSockets, configure Socket.io, manage connection state... it gets complicated fast. But there's a simpler way using Redis Pub/Sub and Server-Sent Events.
The Architecture
Here's the beautiful simplicity of this approach:
- Redis Pub/Sub — Routes messages between servers
- Server-Sent Events — Pushes to browsers (one-way, simple)
- Next.js API Routes — Handles the SSE connections
No WebSocket servers to manage. No sticky sessions. It just works.
Publishing Notifications
When something happens that a user should know about:
import Redis from 'ioredis'
const redis = new Redis(process.env.REDIS_URL)
async function notify(userId, message) {
await redis.publish(
`notifications:${userId}`,
JSON.stringify({
id: crypto.randomUUID(),
...message,
timestamp: Date.now()
})
)
}That's it for the sender side. One line to publish.
The SSE Endpoint
This is where the magic happens:
// app/api/notifications/route.ts
export async function GET(req) {
const userId = await getUserId(req)
const stream = new ReadableStream({
start(controller) {
const sub = new Redis(process.env.REDIS_URL)
sub.subscribe(`notifications:${userId}`)
sub.on('message', (ch, msg) => {
controller.enqueue(`data: ${msg}\n\n`)
})
}
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache'
}
})
}Client-Side Hook
function useNotifications() {
const [items, setItems] = useState([])
useEffect(() => {
const es = new EventSource('/api/notifications')
es.onmessage = (e) => {
const notif = JSON.parse(e.data)
setItems(prev => [notif, ...prev])
toast(notif.title) // Show toast
}
return () => es.close()
}, [])
return items
}Why this works so well
Real-World Usage
Now you can send notifications from anywhere in your app:
// When an order ships
await notify(order.userId, {
title: 'Order Shipped! 📦',
body: 'Your package is on its way'
})
// When someone comments
await notify(post.authorId, {
title: 'New Comment',
body: `${commenter.name} commented on your post`
})Real-time notifications transform how users experience your app. And with Redis Pub/Sub, they're surprisingly easy to implement.
Ready to build something amazing?
Get your Redis database running in 30 seconds. No credit card required.
Start Free →