Building Type-Safe APIs with Nuxt 3 and Prisma
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Choose the right real-time communication strategy. A technical comparison of WebSockets, SSE, and long polling with decision criteria.
Mbeah Essilfie
May 16, 2026 at 06:04 AM
Not all "real-time" needs are equal. Choose based on your actual requirements, not on what sounds coolest.
The simplest approach — client asks "anything new?" repeatedly:
// Client
async function poll() {
while (true) {
try {
const response = await fetch('/api/updates?since=' + lastTimestamp)
const data = await response.json()
if (data.updates.length > 0) {
handleUpdates(data.updates)
lastTimestamp = data.timestamp
}
} catch (e) {
await sleep(5000) // backoff on error
}
await sleep(1000) // poll interval
}
}
Pros: Works everywhere, simple to implement, stateless server Cons: Latency (up to poll interval), wasted requests, server load
Use when: Simple notification checks, legacy browser support needed
Server pushes to client over a persistent HTTP connection:
// Server (Nuxt/Nitro)
export default defineEventHandler((event) => {
setHeader(event, 'Content-Type', 'text/event-stream')
setHeader(event, 'Cache-Control', 'no-cache')
const stream = new ReadableStream({
start(controller) {
const send = (data: unknown) => {
controller.enqueue(`data: ${JSON.stringify(data)}\n\n`)
}
// Subscribe to updates
const unsubscribe = subscribe('updates', send)
event.node.req.on('close', () => {
unsubscribe()
controller.close()
})
},
})
return sendStream(event, stream)
})
// Client
const source = new EventSource('/api/stream')
source.onmessage = (event) => {
const data = JSON.parse(event.data)
handleUpdate(data)
}
source.onerror = () => {
// EventSource auto-reconnects!
}
Pros: Auto-reconnection, simple API, works through most proxies, HTTP/2 multiplexing Cons: Unidirectional (server → client only), text-only, limited connections per domain
Use when: Live feeds, notifications, dashboards, stock tickers
Full-duplex communication channel:
// Server
const wss = new WebSocketServer({ port: 8080 })
wss.on('connection', (ws) => {
ws.on('message', (data) => {
const message = JSON.parse(data.toString())
// Handle client messages
if (message.type === 'subscribe') {
channels.add(ws, message.channel)
}
})
// Push to client
ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }))
})
Pros: Bidirectional, binary data support, lowest latency, established standard Cons: Stateful (scaling is harder), no auto-reconnect, blocked by some proxies
Use when: Chat, multiplayer games, collaborative editing, bidirectional streaming
| Feature | Long Polling | SSE | WebSocket |
|---|---|---|---|
| Direction | Client → Server | Server → Client | Bidirectional |
| Auto-reconnect | Manual | Built-in | Manual |
| Binary data | ❌ | ❌ | ✅ |
| HTTP/2 compatible | ✅ | ✅ | ❌ |
| Proxy-friendly | ✅ | ✅ | ⚠️ |
| Scaling difficulty | Low | Medium | High |
| Browser support | All | All modern | All modern |
Start with the simplest option that meets your requirements. You can always upgrade later.
Fullstack Software Developer
Learn how to build end-to-end type-safe APIs using Nuxt 3 server routes and Prisma ORM for a seamless developer experience.
Go beyond basic utility classes and learn how to build cohesive, maintainable design systems with Tailwind CSS.
Understand the power of Vue 3's Composition API through practical, real-world composable patterns that you can use today.
