@fastify/websocket
Adds first-class WebSocket route support to Fastify, dispatching every upgrade through Fastify's own hooks and router instead of bolting ws on beside it.
Repository Health
Technical Analysis
@fastify/websocket is the official Fastify plugin for handling WebSocket connections. Rather than treating WebSocket upgrades as a separate concern layered on top of the HTTP server, it dispatches every upgrade request through Fastify’s normal routing and hook pipeline — so onRequest, preValidation, and preHandler hooks, decorators, and encapsulation contexts all apply to WebSocket routes exactly as they do to regular HTTP routes. Routes opt in with a simple { websocket: true } route option, or a wsHandler alongside a normal handler when a single route needs to serve both HTTP and WebSocket clients.
Built on top of ws@8, the plugin runs the underlying WebSocket.Server in noServer mode and manages the upgrade handshake itself, giving applications a configurable errorHandler for connection-level errors and a preClose hook for graceful shutdown of open sockets. For testing, it decorates the Fastify instance with injectWS, which uses a Duplexify-based virtual socket pair to simulate a full WebSocket upgrade handshake without opening a real network connection — letting WebSocket routes be tested with the same ergonomics as Fastify’s regular .inject().
The project ships hand-written TypeScript type declarations (checked with tstyche type tests, not compiled from TS source), enforces 100% test coverage via c8, and is maintained by the Fastify core team as one of its official @fastify/* plugins.
What You Get
- A
{ websocket: true }route option that upgrades a GET route to a WebSocket handler while still returning 404s for non-websocket clients hitting the same path if desired - Full Fastify hook support on WebSocket routes —
onRequest,preParsing,preValidation, andpreHandlerall run before the socket is upgraded, so auth and validation logic is reused as-is - A configurable
errorHandlerthat catches both synchronous/async errors thrown in the WS handler anderrorevents from the established socket (e.g. unclean client disconnects) - An
injectWStest helper that simulates a complete upgrade handshake via an in-memory Duplexify stream pair, avoiding real sockets in unit tests - A
preClosehook (with a sane default) for cleanly closing all open WebSocket connections when the Fastify server shuts down - Access to the raw
websocketServer(the underlyingws.Serverinstance) as a Fastify decoration for advanced use cases
Common Use Cases
- Adding a single real-time endpoint (e.g. live notifications or a chat channel) to an existing Fastify HTTP API without standing up a separate WS server
- Building an authenticated WebSocket API where
preValidation/onRequesthooks verify a session or API key before the socket handshake completes - Serving both an HTTP JSON endpoint and a WebSocket stream from the same route path via the
wsHandler+handlerfull-declaration syntax - Wrapping a Fastify WebSocket route in
ws.createWebSocketStreamto read/write it as a Node.js duplex stream instead of rawsend/on('message')calls - Writing fast, deterministic unit tests for WebSocket routes using
injectWSinstead of spinning up a listening server and a realwsclient
Under The Hood
Architecture
The plugin is a single-file (index.js) Fastify plugin wrapped in fastify-plugin so its decorations and hooks escape Fastify’s normal encapsulation boundary. It decorates the instance with ws (a per-request boolean), websocketServer (the raw ws.Server, run in noServer mode), and injectWS (a testing helper). Its core trick is an onRoute hook that wraps every route’s handler: if the incoming request carries an upgrade socket, it hijacks the Fastify reply and dispatches to a wsHandler instead of the normal HTTP handler, routing the upgrade itself so all of Fastify’s own hooks and routing logic still apply. injectWS builds a virtual socket pair from two PassThrough streams joined by Duplexify, then emits a fake HTTP upgrade response through it — a deliberate low-level technique to make WebSocket routes testable without a real network socket. The design tightly couples this plugin to Fastify’s hook/route internals by intent — it is not a general-purpose module, but an integration layer.
Tech Stack
Plain CommonJS JavaScript with hand-authored TypeScript declarations (types/index.d.ts), rather than a compiled TypeScript source. Runtime dependencies are minimal and precise: ws for the WebSocket protocol implementation, fastify-plugin for encapsulation-safe registration, and duplexify for the stream-pairing used by injectWS. It targets Fastify v5 as a peer plugin and uses Node’s built-in http, stream, and crypto modules directly rather than additional abstractions. Linting runs through neostandard’s flat ESLint config, type declarations are checked with tstyche, and coverage is measured with c8.
Code Quality
The test suite spans four files covering base behavior, hooks, injectWS, and router interactions, run via Node’s built-in test runner under c8 --100 — meaning the project fails its own test command if coverage drops below 100%, a strong and unusually strict quality bar. Error handling is explicit: a documented, overridable errorHandler covers both handler exceptions and socket-level error events, with clear documentation of exactly which Fastify hooks run before versus after the WebSocket upgrade. CI runs on GitHub Actions, and the API is exercised through both runtime tests and static type tests, giving reasonable confidence in the shipped .d.ts file staying accurate.
What Makes It Unique
Most WebSocket-on-HTTP-framework integrations treat the upgrade as a side channel bypassing the framework’s own middleware/hook pipeline. This plugin instead re-dispatches every upgrade through Fastify’s actual router, so authentication, validation, and other hooks apply identically to WebSocket and HTTP routes, and unmatched routes are still governed by Fastify’s normal 404 handling. Combined with the injectWS virtual-socket testing helper — a genuinely uncommon technique for making WebSocket routes as easy to unit test as regular HTTP routes — the library solves a real ergonomics gap rather than just wrapping ws in a thin decorator.
Used by 7 apps in this directory
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
Colanode
Knowledge Management · Team Chat · Collaboration
Local-first, self-hosted workspace that combines real-time chat, Notion-style pages, and structured databases — all synced via CRDTs so you work offline without losing a keystroke.
Infisical
Security · Devops
The open-source platform for secrets, certificates, privileged access, and AI agent security — all in one self-hostable system.
Onlook
Design Tools · AI Design Tools
An open-source, AI-first visual editor that lets designers and developers build, style, and deploy React apps directly in code — no handoff required.
OpenPanel
Analytics
Open-source Mixpanel alternative with session replay, MCP integration, and privacy-first product analytics you fully control.
optio
AI Agents · AI Code Assistants
Self-hosted AI agent workflow orchestration that runs on your Kubernetes cluster — from ticket intake to squash-merged PR, entirely within your infrastructure.
Super Productivity
Productivity · Project Management
A privacy-respecting, local-first task manager with built-in timeboxing, Pomodoro timer, and deep integrations for Jira, GitHub, GitLab, and CalDAV — no accounts, no data collection, ever.