Server-Sent Events in TypeScript: A Step-by-Step Guide for Real Projects

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Server-Sent Events in TypeScript: Data Streaming Without the Headache

\n\n

Imagine: your server generates data — logs, notifications, currency exchange rate updates — and needs to instantly send them to the frontend. WebSocket? Powerful, but overkill. Polling? Slow and consumes bandwidth. There is a third path — elegant, simple, and incredibly useful: Server-Sent Events (SSE).

\n\n

In this article, we will break down SSE in TypeScript from start to finish. We will write a client and server, learn how to handle errors and reconnect, and most importantly — understand when SSE truly wins over other approaches. Let's go!

\n\n

What are Server-Sent Events and Why Do You Need Them?

\n\n

Server-Sent Events is an HTML5 standard that allows a server to send data to a client over a single HTTP connection in real time. Unlike WebSocket, SSE is one-way: only the server sends messages. But that is precisely its strength — it is extremely simple and requires no additional libraries.

\n\n

When to Choose SSE?

\n\n
    \n
  • One-way streaming: notifications, logs, currency rates, stock tickers.
  • \n
  • Simple integration: works via the standard EventSource in the browser — no npm packages needed.
  • \n
  • Automatic reconnection: the browser restores the connection on its own when it drops.
  • \n
  • HTTP/2 compatibility: multiplexing does not interfere, unlike WebSocket.
  • \n
\n\n

But remember: SSE cannot send data from the client to the server (use regular POST requests for that) and is not supported in older browsers (looking at you, IE).

\n\n

Server Side: Writing SSE in TypeScript + Express

\n\n

Let's start with the backend. We will create a simple server using Node.js with Express and TypeScript. Install the dependencies:

\n\n
npm init -y\nnpm install express cors\nnpm install -D typescript @types/express @types/node ts-node\nnpx tsc --init
\n\n

Now let's write the server itself. The key point is setting the correct headers and the message format.

\n\n
// server.ts\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\n\n// SSE endpoint\napp.get('/events', (req: Request, res: Response) => {\n  // Set headers for SSE\n  res.writeHead(200, {\n    'Content-Type': 'text/event-stream',\n    'Cache-Control': 'no-cache',\n    'Connection': 'keep-alive',\n  });\n\n  // Send initial message\n  res.write('data: {"message": "Connection established"}\\n\\n');\n\n  // Send an event every 3 seconds\n  const intervalId = setInterval(() => {\n    const data = JSON.stringify({\n      time: new Date().toISOString(),\n      value: Math.random() * 100,\n    });\n    res.write(`data: ${data}\\n\\n`);\n  }, 3000);\n\n  // Handle client disconnect\n  req.on('close', () => {\n    clearInterval(intervalId);\n    res.end();\n    console.log('Client disconnected');\n  });\n});\n\nconst PORT = 3000;\napp.listen(PORT, () => console.log(`SSE server running on port ${PORT}`));
\n\n

Note the format: each message starts with data: and ends with two newlines \\n\\n. You can also specify id, event, and retry — but this is the basics.

\n\n

Sending Named Events

\n\n

Sometimes you need to distinguish between message types. Let's add the event field:

\n\n
res.write('event: update\\n');\nres.write(`data: ${JSON.stringify({ id: 1, title: 'New post' })}\\n\\n`);\n\n// And then — another event\nres.write('event: notification\\n');\nres.write('data: {"level": "info", "text": "Server is running"}\\n\\n');
\n\n

On the client side, we will be able to subscribe to specific events.

\n\n

Client Side: Receiving Events in TypeScript

\n\n

Now let's write the client. In the browser, the built-in EventSource is used. But if

Blogs

Book Recommendations