reconnecting-websocket

A drop-in WebSocket wrapper for Web, Node.js, and React Native that auto-reconnects with configurable backoff and message buffering.

Library
npm
v4.4.0
1,314stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
47/100Fair
Development Activity0
Maintenance20
Community68
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture70
Code Quality82
Innovation55
Learning Curve80

reconnecting-websocket is a small, dependency-free wrapper around the native WebSocket API that transparently reconnects a dropped connection instead of leaving the caller to detect and recover from disconnects manually. It exposes the exact same interface as the browser’s WebSocket object — same methods, same Level0/Level2 event model, same readyState constants — so it can be swapped in as a drop-in replacement with no changes to surrounding code.

Under the hood it tracks connection attempts with an exponential backoff (configurable min/max delay and growth factor), enforces a connection timeout so a hung handshake doesn’t stall forever, and treats a connection as “stable” only after it has stayed open past a minimum uptime — resetting the retry counter at that point rather than after every successful open. Messages sent while disconnected are queued (up to a configurable cap) and flushed in order once the connection re-opens, so callers don’t have to buffer outgoing data themselves.

Because it takes an injectable WebSocket constructor, the same library works in a browser, inside a Service Worker, in Node.js (paired with the ws package), or in React Native — anywhere a WebSocket-shaped constructor is available. The URL can also be a synchronous or async provider function, which supports round-robin server selection or fetching a fresh auth token before each reconnection attempt.

What You Get

  • A WebSocket-compatible class with the same methods, properties, and Level0/Level2 event model as the native WebSocket, so it can replace new WebSocket(...) with no other code changes
  • Automatic reconnection with configurable exponential backoff (min/max delay, growth factor) and a connection timeout that aborts hung handshakes
  • A minimum-uptime check that only resets the retry counter once a connection has proven stable, avoiding tight reconnect loops against a flapping server
  • Message buffering that enqueues send() calls made while disconnected (up to a configurable cap) and flushes them in order once the socket reopens
  • Support for static, synchronous, or async URL providers, enabling round-robin endpoint selection or fetching a fresh token before each connection attempt
  • An injectable WebSocket constructor option, making the library usable in Node.js (with the ws package), Service Workers, and React Native, not just browsers

Common Use Cases

  • Keeping a real-time dashboard or chat UI connected to a backend WebSocket server across flaky networks or brief server restarts
  • Running a persistent WebSocket connection from a Node.js service or CLI tool using the ws package as the underlying implementation
  • Maintaining a live connection in a React Native app where network transitions (Wi-Fi to cellular, backgrounding) frequently drop sockets
  • Rotating between multiple WebSocket endpoints with a round-robin URL provider for simple client-side load distribution
  • Reconnecting with a freshly fetched auth token on each attempt via an async URL provider, for APIs that require per-connection authentication

Under The Hood

Architecture The library is a single class, ReconnectingWebSocket (in reconnecting-websocket.ts), that composes over a real WebSocket instance rather than extending it: _connect() resolves the URL (sync, string, or async provider), instantiates the underlying WebSocket, and wires _handleOpen/_handleMessage/_handleError/_handleClose handlers that call back into the class’s own listener maps and public on* callbacks. Reconnection is driven entirely by state flags (_connectLock, _shouldReconnect, _closeCalled) and two timers (_connectTimeout, _uptimeTimeout) rather than a formal state machine, keeping the control flow compact but meaning correctness depends on careful ordering of flag resets across close(), reconnect(), and the error/close handlers. A companion events.ts module defines lightweight Event/ErrorEvent/CloseEvent classes so the library doesn’t depend on the DOM’s Event constructor, which is what keeps it usable outside a browser (Node.js, React Native). What breaks if this abstraction changes: any consumer relying on exact native WebSocket event shapes would need the custom event classes to keep tracking the same fields. Tech Stack Written in strict TypeScript (tsconfig.json targets ES5 with dom/es6 libs) and built with Rollup (rollup-plugin-typescript2) into IIFE, AMD, CommonJS, and ES module bundles, then minified with uglify-es for the browser build. It has zero runtime dependencies ("dependencies": {} in package.json) — the only dependency-shaped input is an injectable WebSocket constructor supplied by the caller, commonly the ws package in Node.js. Linting runs through eslint with @typescript-eslint, formatting through prettier, and Git hooks are enforced with husky + lint-staged on commit. Code Quality Tests live in __tests__/test.ts (via Jest with ts-jest) and are extensive — over 800 lines covering constructor validation, backoff timing, message buffering, timeout handling, and reconnect/close semantics against a real local ws server rather than mocks, plus a companion unresponsive-server.js fixture for exercising the connection-timeout path. Coverage is collected with jest --coverage and reported to Coveralls in CI. Error handling is explicit throughout (throw Error(...) for invalid WebSocket constructors or malformed URLs, guarded try/catch around socket teardown), and the codebase is fully typed with strict: true enabled. What Makes It Unique Its main differentiator is scope discipline: rather than building a general real-time abstraction (channels, pub/sub, protocol framing), it solves exactly one problem — reconnection — while staying byte-for-byte compatible with the native WebSocket API, so it can be dropped into existing code with a single import change. The injectable-constructor design is what lets the same small library serve browsers, Node.js, Service Workers, and React Native without separate platform builds.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search