Usage recipes
Better SSE works with any web-server framework that uses the Node HTTP module or the Fetch API.
This section shows example usage with some popular HTTP libraries.
Feel free to submit a PR with a minimal example for another framework!
import { createServer } from "node:http"import { createSession } from "better-sse"
const server = createServer(async (req, res) => { switch (req.url) { case "/sse": { const session = await createSession(req, res)
session.push("Hello world!")
break } default: { res.writeHead(404).end() break } }})
server.listen(8080)
import { createSecureServer } from "node:http2"import { createSession } from "better-sse"
const server = createSecureServer({key, cert}, async (req, res) => { switch (req.url) { case "/sse": { const session = await createSession(req, res)
session.push("Hello world!")
break } default: { res.stream.respond({ ":status": 404 }) break } }})
server.listen(8080)
import { createResponse } from "npm:better-sse"
Deno.serve({ port: 8080 }, (request) => { const url = new URL(request.url)
switch (url.pathname) { case "/sse": { return createResponse(request, (session) => { session.push("Hello world!") }) } default: { return new Response("404 Not Found", { status: 404, headers: { "Content-Type": "text/plain", }, }) } }})
import { createResponse } from "better-sse"
Bun.serve({ port: 8080, routes: { "/sse": (req) => createResponse( request, // Set the keep-alive interval to below // Bun's default idle timeout of ten (10) seconds { keepAlive: 8000 }, (session) => { session.push("Hello world!") } ), }, fetch() { return new Response("404 Not Found", { status: 404, headers: { "Content-Type": "text/plain", }, }) },})
Using @mjackson/node-fetch-server
as an example of a server framework that implements the Fetch API.
import { createServer } from "node:http"import { createRequestListener, type FetchHandler } from "@mjackson/node-fetch-server"import { createResponse } from "better-sse"
const handler: FetchHandler = (request) => { const url = new URL(request.url)
switch (url.pathname) { case "/sse": { return createResponse(request, (session) => { session.push("Hello world!") }) } default: { return new Response("404 Not Found", { status: 404, headers: { "Content-Type": "text/plain", }, }) } }}
const server = createServer(createRequestListener(handler))
server.listen(8080)
import express from "express"import { createSession } from "better-sse"
const app = express()
app.get("/sse", async (req, res) => { const session = await createSession(req, res) session.push("Hello world!")})
app.listen(8080)
import Koa from "koa"import Router from "@koa/router"import { createSession } from "better-sse"
const app = new Koa()const router = new Router()
router.get("/sse", async (ctx) => { // Prevent Koa sending a response and closing the connection ctx.respond = false
const session = await createSession(ctx.req, ctx.res)
session.push("Hello world!")})
app.use(router.routes())
app.listen(8080)
import { Hono } from "hono"import { serve } from "@hono/node-server"import { createResponse } from "better-sse"
const app = new Hono()
app.get("/sse", (c) => createResponse(c.req.raw, (session) => { session.push("Hello world!") }))
serve({ fetch: app.fetch, port: 8080 })
Requires first enabling the Node.js compatibility polyfills:
{ compatibility_flags: ["nodejs_compat"], compatibility_date: "2024-09-23",}
import { createResponse } from "better-sse"
export default { async fetch(request, env, ctx): Promise<Response> { const url = new URL(request.url)
switch (url.pathname) { case "/sse": { return createResponse(request, (session) => { session.push("Hello world!") }) } default: { return new Response("Not Found", { status: 404, headers: { "Content-Type": "text/plain" }, }) } } }} satisfies ExportedHandler<Env>
import { createResponse } from "better-sse"
export async function GET(request: Request) { return createResponse(request, (session) => { session.push("Hello world!") })}
import { NextApiRequest, NextApiResponse } from "next"import { createSession } from "better-sse"
export default async function handler( req: NextApiRequest, res: NextApiResponse) { const session = await createSession(req, res)
session.push("Hello world!")}
import { Controller, Get, Req, Res } from "@nestjs/common"import { Request, Response } from "express"import { createSession } from "better-sse"
@Controller()export class SseController { @Get("sse") async sse(@Req() req: Request, @Res() res: Response) { const session = await createSession(req, res)
session.push("Hello world!") }}
import { Controller, Get, Req, Res } from "@nestjs/common"import { FastifyReply, FastifyRequest } from "fastify"import { createSession } from "better-sse"
@Controller()export class SseController { @Get("sse") async sse(@Req() req: FastifyRequest, @Res() res: FastifyReply) { const session = await createSession(req.raw, res.raw)
session.push("Hello world!") }}
import Fastify from "fastify"import { createSession } from "better-sse"
const fastify = Fastify()
fastify.get("/sse", async (request, reply) => { const session = await createSession(request.raw, reply.raw)
session.push("Hello world!")})
fastify.listen({ port: 8080 })
import { LoaderFunction } from "@remix-run/node"import { createResponse } from "better-sse"
export const loader: LoaderFunction = ({ request }) => createResponse(request, (session) => { session.push("Hello world!") })
import router from "@adonisjs/core/services/router"import { createSession } from "better-sse"
router.get("/sse", async ({ request, response }) => { const session = await createSession(request.request, response.response)
session.push("Hello world!")})
import Hapi from "@hapi/hapi"import { createSession } from "better-sse"
const init = async () => { const server = Hapi.server({ port: 8080, host: "localhost", })
server.route({ method: "GET", path: "/sse", handler: async ({ raw }, { abandon }) => { const session = await createSession(raw.req, raw.res)
session.push("Hello world!")
// Prevent Hapi from interacting further with the response stream return abandon }, })
await server.start()}
init()