Node.js - WebSocket support
Introduction
WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection. This extension supports the following WebSocket libraries:
- Native WebSocket API — built-in browser WebSocket constructor (also available in Node.js ≥ 22)
- ws — the most widely used WebSocket library for Node.js
- websocket npm package — WebSocket client and server implementation
Objects
| Icon | Metamodel name | Description |
|---|---|---|
![]() |
TypeScript WebSocket Server | Represents a WebSocket server endpoint identified by its path |
![]() |
TypeScript WebSocket Client | Represents a WebSocket client connection identified by its URL |
![]() |
TypeScript Unknown WebSocket Client | Represents a WebSocket client whose URL cannot be statically resolved |
A WebSocketServer with name {} is created when the server path cannot be statically determined
(for example when the path is passed as a runtime parameter). A server with path {} is treated
as a catch-all endpoint.
Links
| Link type | From | To | Created when |
|---|---|---|---|
callLink |
TypeScript WebSocket Server | TypeScript Function / Method | A handler is registered on the server (on, route config) |
callLink |
TypeScript Function / Method | TypeScript WebSocket Server | A function sends a message to clients (broadcast/publish) — see filtering rule below |
callLink |
TypeScript Function / Method | TypeScript WebSocket Client | A function calls send() on a client connection — see filtering rule below |
callLink |
TypeScript WebSocket Client | TypeScript Function / Method | A handler is registered on the client (on, onmessage, addEventListener) |
Send links — semantic meaning
A send link (callLink from a function to a WebSocket object) represents that the function
actively pushes data to a WebSocket peer. In the call graph this makes the function a caller of
the WebSocket server or client object, complementing the callee links that already show which
functions receive messages from it.
Two kinds of send links are created:
- Function → WebSocket Server: the function broadcasts or publishes a message to all connected
clients (e.g.
wss.clients.forEach,app.publish,wsServer.broadcast). - Function → WebSocket Client: the function sends a message over an outbound client connection
(e.g.
ws.send(data)called from application code that is not itself a message handler).
Send link filtering
To avoid redundant links, send links are suppressed when the sending function already has a relationship with the WebSocket object through a handler registration:
| Situation | Example | Result |
|---|---|---|
| The sending function is already a registered server handler (direct callee of the server) | ws.send() inside a wss.on('connection', fn) callback |
Suppressed — fn is already linked as a callee of the server |
| The sending function is already a registered client event handler (direct callee of the client) | ws.send() inside ws.onopen = fn or ws.addEventListener('message', fn) |
Suppressed — fn is already linked as a callee of the client |
| The sending function is not a registered handler | wsServer.broadcast() called from a scheduler or REST endpoint |
Created — the send link appears in the call graph |
In short: a send link is only created when the sending function has no existing relationship with the WebSocket object. This keeps the call graph clean and avoids showing the same function as both a callee (handler) and a caller (sender) of the same object.
Supported API methods
ws library
Server side
| API method | Object created / linked | Link type |
|---|---|---|
new WebSocketServer({ path }) |
TypeScript WebSocket Server | — |
wss.on('connection', fn) |
fn linked as callee of server | callLink |
ws.send(data) called from a registered handler |
suppressed (see filtering rule) | — |
wss.clients.forEach(fn) + client.send(data) |
fn linked as caller (send link) | callLink |
Client side
| API method | Object created / linked | Link type |
|---|---|---|
new WebSocket(url) |
TypeScript WebSocket Client | — |
ws.on('message', fn) |
fn linked as callee of client | callLink |
ws.send(data) from a handler |
suppressed (see filtering rule) | — |
ws.send(data) from other code |
fn linked as caller (send link) | callLink |
websocket npm package
Server side
| API method | Object created / linked | Link type |
|---|---|---|
new WebSocketServer({ httpServer }) |
TypeScript WebSocket Server | — |
wsServer.on('request', fn) |
fn linked as callee of server | callLink |
conn.send(), conn.sendUTF(), conn.sendBytes() from a request handler |
suppressed (see filtering rule) | — |
wsServer.broadcast(), wsServer.broadcastUTF(), wsServer.broadcastBytes() from non-handler |
fn linked as caller (send link) | callLink |
Client side
| API method | Object created / linked | Link type |
|---|---|---|
new WebSocketClient() + client.connect(url) |
TypeScript WebSocket Client | — |
client.on('connect', fn) |
fn linked as callee of client | callLink |
conn.send(), conn.sendUTF(), conn.sendBytes() from non-handler |
fn linked as caller (send link) | callLink |
new W3CWebSocket(url) |
TypeScript WebSocket Client | — |
ws.onmessage = fn / ws.addEventListener(...) |
fn linked as callee of client | callLink |
ws.send(data) from a handler |
suppressed (see filtering rule) | — |
ws.send(data) from other code |
fn linked as caller (send link) | callLink |
Native WebSocket API
Client side
| API method | Object created / linked | Link type |
|---|---|---|
new WebSocket(url) |
TypeScript WebSocket Client | — |
ws.onmessage = fn |
fn linked as callee of client | callLink |
ws.onopen = fn |
fn linked as callee of client | callLink |
ws.onclose = fn / ws.onerror = fn |
fn linked as callee of client | callLink |
ws.addEventListener('message', fn) |
fn linked as callee of client | callLink |
ws.send(data) from a handler |
suppressed (see filtering rule) | — |
ws.send(data) from other code |
fn linked as caller (send link) | callLink |
Example
When analyzing the following files
server.ts
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 8080, path: '/chat' });
// callLink: wss ──→ connection_PARAM_1 (callee — server registers this handler)
wss.on('connection', (ws) => {
// callLink: wss ──→ message_PARAM_1 (callee — server registers this inner handler)
ws.on('message', (data) => {
// No send link: this function is already a callee of the server,
// so ws.send() is suppressed by the filtering rule.
ws.send('echo: ' + data);
});
});
// callLink: broadcastAll ──→ wss (send link — broadcastAll is NOT a server handler)
function broadcastAll(msg: string) {
wss.clients.forEach((client) => {
client.send(msg);
});
}
client.ts
const ws = new WebSocket('wss://example.com/chat');
// callLink: ws ──→ onMsg (callee — client registers this handler)
ws.onmessage = function onMsg(event) {
// No send link: onMsg is already a callee of the client,
// so ws.send() is suppressed by the filtering rule.
ws.send('ack');
};
// callLink: ws ──→ onOpen (callee — client registers this handler)
ws.onopen = function onOpen() {
// Also suppressed: onOpen is a callee of the client.
ws.send(JSON.stringify({ action: 'subscribe' }));
};
// callLink: sendMessage ──→ ws (send link — sendMessage is NOT a client handler)
function sendMessage(text: string) {
ws.send(text);
}
you will get the following result:

Known limitations
- Client-to-server linking works only when the WebSocket server endpoint is declared using the library’s built-in path option. Servers that perform path matching through custom upgrade-handling logic are not currently supported. The server path must exactly match the trailing path of the client URL. For example, a server configured with /chat matches a client connecting to ws://example.com/chat, but a server configured with / does not match a client connecting to ws://example.com/chat
- Host and port are currently ignored during linking, which may result in false links between clients and servers running on different hosts and/or ports.


