websocket

Minimal, idiomatic Go WebSocket library with full context.Context support, zero dependencies, and Wasm compatibility.

Library
Go
vv1.8.15
5,441stars
ISC

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
57/100Fair
Development Activity28
Maintenance40
Community60
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture78
Code Quality88
Innovation62
Learning Curve65

coder/websocket (formerly nhooyr/websocket) is a minimal, idiomatic implementation of the RFC 6455 WebSocket protocol for Go. It focuses on a small, well-documented API surface, full context.Context support for cancellation and timeouts, and zero external dependencies, while passing the complete Autobahn WebSocket test suite for protocol compliance.

The library supports zero-allocation reads and writes, concurrent writes, RFC 7692 permessage-deflate compression, a close handshake, and a net.Conn wrapper for interoperability with existing networking code. It also compiles to Wasm for browser use and ships a wsjson subpackage with JSON/protobuf message helpers, making it a drop-in choice for both WebSocket servers and clients in Go.

What You Get

  • RFC 6455 compliant WebSocket client and server via Dial and Accept, verified against the Autobahn test suite
  • context.Context-aware API for cancellation, timeouts, and structured concurrency
  • Zero-allocation reads and writes plus support for concurrent writes on the same connection
  • RFC 7692 permessage-deflate compression negotiation via CompressionMode
  • A net.Conn wrapper (NetConn) for reusing existing net.Conn-based code with WebSocket transport
  • wsjson subpackage with JSON and protobuf message read/write helpers
  • Wasm compilation support for browser environments

Common Use Cases

  • Building a real-time chat or notification server without pulling in a heavy WebSocket framework
  • Proxying or wrapping a WebSocket connection as a net.Conn to reuse existing streaming code
  • Adding a low-allocation WebSocket transport to a high-throughput Go service
  • Compiling a Go WebSocket client to Wasm for use inside a browser

Under The Hood

Architecture The library is organized around a central Conn struct (conn.go) that owns buffered readers/writers (bufio.Reader/Writer), separate mutexes for read state, write state, and close-handshake state, plus atomic flags for cancellation and closing status. Public entry points Dial (dial.go) and Accept (accept.go) perform the HTTP Upgrade handshake and construct a Conn; from there Reader/Read (read.go) and Writer/Write (write.go) handle framing, masking (mask.go, mask_asm.go), and optional permessage-deflate compression (compress.go) using internal helpers under internal/ (bpool for buffer pooling, errd for error wrapping, util for shared helpers, xsync for cross-goroutine primitives). Platform-specific files (netconn_js.go/netconn_notjs.go, ws_js.go) isolate the Wasm build path from the native one via build tags. This is a flat, single-purpose library rather than a layered application — its dependency direction runs from the public Conn API down into internal masking/compression/pooling helpers, and changing the core Conn struct or its mutex-guarded state would ripple through nearly every exported method.

Tech Stack The module (go 1.23) declares zero third-party dependencies — go.sum is empty — and is built entirely on the Go standard library: net/http for the client and server-side handshake (Dial uses net/http.Client), bufio for framed I/O, compress/flate for RFC 7692 permessage-deflate, and crypto/sha1 plus encoding/base64 for the WebSocket handshake key exchange. Wire-level masking is implemented in pure Go (mask_go.go) with hand-written amd64 and arm64 assembly fast paths (mask_amd64.s, mask_arm64.s) selected at build time. A wsjson subpackage adds JSON/protobuf message helpers, and Wasm builds swap in ws_js.go/internal/wsjs to wrap the browser’s native WebSocket API instead of implementing the wire protocol directly. Build and test tooling is a Makefile plus shell scripts under ci/ (fmt.sh, lint.sh, test.sh, bench.sh) run through GitHub Actions.

Code Quality The repo carries an extensive test suite spanning protocol conformance (autobahn_test.go running the Autobahn testsuite) and unit tests for accept, dial, close, compress, conn, frame, and mask behavior, plus an internal/test/wstest package providing an in-memory pipe/echo test harness and internal/test/assert for lightweight assertions. Errors are wrapped with fmt.Errorf and %w throughout, and a dedicated internal/errd package standardizes error wrapping on Close. CI runs formatting and lint checks on every push and PR via GitHub Actions, and the test job uploads a coverage report as an artifact with a live coverage badge in the README. Naming follows idiomatic Go conventions with short receiver names and full godoc-style comments on exported types and methods.

What Makes It Unique Its differentiation is not a novel wire protocol but a deliberately smaller, more idiomatic API surface than the dominant gorilla/websocket, built natively around context.Context for every blocking call (rather than deadline-based cancellation), with zero-allocation reads/writes, safe concurrent writes without external synchronization, and a NetConn adapter that lets a WebSocket connection be used anywhere a net.Conn is expected. It also ships hand-optimized amd64/arm64 assembly for the masking hot path for a meaningful speedup over a pure-Go implementation, and compiles cleanly to Wasm by swapping the transport implementation for the browser’s native WebSocket object, an option most native-protocol Go WebSocket libraries don’t offer. These are ergonomic and performance refinements on well-understood WebSocket semantics rather than a new capability class.

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