Skip to main content

graphql-transport-ws

subprotocol

graphql-transport-ws is the modern WebSocket subprotocol for GraphQL subscriptions, maintained by The Guild. It replaces the older subscriptions-transport-ws. Uses the subprotocol identifier graphql-transport-ws. Messages are JSON objects with a type field (connection_init, subscribe, next, error, complete). Resolves several protocol problems in the legacy protocol: server-initiated keep-alives, proper error propagation, and clean stream termination.

Details

GraphQL subscriptions over WebSocket use a structured message envelope on top of the WebSocket transport.

Protocol messages: connection_init: client sends first, optionally with payload for auth context. connection_ack: server acknowledges and may include payload. ping/pong: bidirectional keep-alive (server OR client can initiate). subscribe: client starts a subscription with id, query, variables, extensions. next: server pushes a subscription result (data, errors). error: server signals a fatal subscription error. complete: server or client terminates a specific subscription by id.

Multiple subscriptions per connection: Each subscription has a unique id. The client manages multiple concurrent subscriptions over one WebSocket connection.

Migration from subscriptions-transport-ws: The legacy protocol (subprotocol: graphql-ws) had: no server pings, broken error handling, connection closure on any error. The new protocol (graphql-transport-ws) is used by Apollo Client 3+, urql 2+, and all new implementations. Old subprotocol identifiers differ: old=graphql-ws, new=graphql-transport-ws.

Handshake example

HTTP Upgrade negotiation
# graphql-transport-ws handshake
GET /graphql HTTP/1.1
Host: api.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: graphql-transport-ws

# Server response
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: graphql-transport-ws

# Client sends connection_init
{"type":"connection_init","payload":{"Authorization":"Bearer token"}}

# Server acknowledges
{"type":"connection_ack"}

# Client subscribes (id is client-generated)
{"id":"1","type":"subscribe","payload":{"query":"subscription { newMessages { text } }"}}

# Server pushes results
{"id":"1","type":"next","payload":{"data":{"newMessages":{"text":"Hello"}}}}

# Client or server terminates subscription
{"id":"1","type":"complete"}

See Also