Socket.IO adds delivery plumbing above WebSocket
Socket.IO 4.8.3 gives JavaScript applications a Node.js server, browser and Node.js clients, and a named-event API. Engine.IO begins with HTTP long-polling and attempts an upgrade to WebSocket, which helps connections survive proxies or networks that reject an immediate WebSocket handshake. Automatic reconnection, heartbeats, acknowledgements, binary payloads, rooms, and namespaces cover much of the repetitive work behind chat, collaboration, live status, and multiplayer interfaces.
That convenience creates a protocol boundary. A Socket.IO packet includes its type, namespace, and sometimes an acknowledgement identifier. A normal WebSocket client therefore cannot talk to this server, and the Socket.IO client cannot talk to an ordinary WebSocket endpoint. If another team, browser component, or device already speaks standard WebSocket, adopting Socket.IO means giving that participant a compatible client or building a separate bridge.
The default promise is ordered, at-most-once delivery
Socket.IO preserves message order while switching between its 2 transports, but its default arrival guarantee is at most once. A connection can break while an event is in flight, leaving the sender without proof that the other side received it. Clients buffer some outgoing events while disconnected; servers do not automatically retain missed events for disconnected clients. This distinction matters far more than the friendly emit API suggests.
Client-to-server retries can add an acknowledgement timeout and a fixed retry count. Server-to-client durability remains application work: assign each event an ID, persist it, track the client's last processed offset, and replay later records after reconnect. A browser refresh can also discard pending client events. Payment state, job completion, or anything else that users cannot afford to miss needs storage and idempotency outside Socket.IO.
What happened when we ran it
Our sandbox cloned commit 1d4269c with 843 files, about 57,646 lines of source, and a 17.3 MB checkout. Npm installed 991 packages in 97 seconds and occupied 530 MB on disk. The audit found 0 known vulnerabilities: 0 critical, 0 high, 0 moderate, and 0 low. Those figures came from a fresh unprivileged Debian container with 3 CPUs and 8 GB of RAM.
The repository root exposed no build script or target, so our build step was skipped. It also exposed no test script or target, so our test step was skipped and produced no pass count. The scan found 14 CI workflow files, npm workspaces, no Dockerfile, and no tests directory. Package-level scripts exist deeper in the monorepo, but the lab result is plain: the root commands available to our harness did not verify the checkout.
Multiple servers require affinity or WebSocket-only clients
A single Node.js process can attach Socket.IO to an HTTP server without external credentials. The repository's contributor guide raises the source-development baseline to Node.js 18+ and npm 7+ because it uses workspaces. Production configuration grows when traffic spans processes or machines. The scaling guide says polling requests for one session must reach the server that created that session, usually through sticky sessions.
Teams can avoid that affinity requirement by disabling long-polling and accepting WebSocket-only connections, which also removes the fallback that makes Socket.IO attractive on difficult networks. Messages must still move between server instances through an adapter. The official guide covers Redis, Redis Streams, MongoDB, Postgres, and cluster choices, and the capabilities differ. Infrastructure selection affects recovery as well as broadcasting, so adapters are more than interchangeable plumbing.
Recovery helps after a disconnect but cannot be trusted alone
Connection-state recovery can restore a socket ID, rooms, socket data, and missed packets after a temporary break. The documentation also says recovery can fail and applications must handle full resynchronization. Adapter support varies: the built-in adapter and Redis Streams support recovery, while the Redis Pub/Sub adapter does not. A setting that skips middleware on successful recovery can also bypass a fresh authorization check for a newly blocked user.
The documented handshake needs an offset from a previously received event. The recovery guide states that the server must send at least 1 event before recovery can succeed. Open issue 5538 shows the practical consequence on Socket.IO 4.8.1: a client that joined a room and disconnected before receiving any event came back with a new ID and lost room data. Quiet alert channels should test that exact case and retain a resync path.
Current maintenance is active, with operational limits spelled out
GitHub showed 63,211 stars, 200 combined issues and pull requests, and a last push on September 8, 2026. The latest release, 4.8.3, arrived on March 18, 2026 and fixed io.close() throwing on a stopped server. Recent issue and pull request updates in September cover packet typing, polling payload limits, buffered packets, parsing, and recovery, so the six-month release gap does not read as abandonment.
Documentation is the project's strongest buying argument. The main repository README is brief, but the linked site is candid about at-most-once delivery, failed recovery, adapter compatibility, CORS, reverse proxies, and session affinity. Socket.IO is a good default when every participant can use its protocol and the application values connection handling over minimalism. It is a poor substitute for durable messaging, and its pleasant event syntax should never be mistaken for one.

