Server-Sent Events don't work in Next API routes
See original GitHub issueBug report
Describe the bug
When using Next’s API routes, chunks that are written with res.write aren’t sent until after res.end() is called.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
- Create the following API route in a Next app:
export default async (req, res) => {
let intervalID = null
res.setHeader('Content-Type', 'text/event-stream')
res.write('data: CONNECTION ESTABLISHED\n')
const end = () => {
if (intervalID) {
clearTimeout(intervalID)
}
}
req.on('aborted', end)
req.on('close', end)
const sendData = () => {
const timestamp = (new Date).toISOString()
res.write(`data: ${timestamp}\n`)
}
intervalID = setInterval(sendData, 1000)
}
- Connect to the route with a tool that supports Server-Sent Events (i.e. Postwoman).
Expected behavior
The route sends a new event to the connection every second.
Actual behavior
The route doesn’t send any data to the connection unless a call to res.end() is added to the route.
System information
- OS: macOS
- Version of Next.js: 9.1.5
Additional context
When using other HTTP frameworks (Express, Koa, http, etc) this method works as expected. It’s explicitly supported by Node’s http.incomingMessage and http.ServerResponse classes which, from what I understand, Next uses as a base for the req and res that are passed into Next API routes.
I’d hazard a guess that #5855 was caused by the same issue, but considered unrelated because the issue was obscured by the express-sse library.
There are also two Spectrum topics about this (here and here) that haven’t garnered much attention yet.
Supporting Websockets and SSE in Next API routes may be related, but fixing support for SSE should be a lower barrier than adding support Websockets. All of the inner workings are there, we just need to get the plumbing repaired.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:3
- Comments:28 (3 by maintainers)

Top Related StackOverflow Question
Thanks for all the effort on this ticket, folx! I wanted to pop in and say I think we can mark it as resolved. Here’s a quick TL;DR:
Code from above comment, if you want to try