GraphQL Subscriptions

Queries and mutations are request-response. Subscriptions are GraphQL's third operation type, for real-time updates: the client subscribes to an event with a selection set, and the server pushes a result each time that event occurs, shaped exactly like a query response. Typical uses are chat messages, notifications, live order status, collaborative editing presence, and dashboards.

Subscriptions keep GraphQL's strengths (typed schema, client-chosen fields) but bring the operational concerns of real-time systems: long-lived connections, fan-out to many subscribers across multiple server instances, per-event authorization, and reconnection. Knowing those trade-offs helps you decide when subscriptions are worth it versus simpler polling.

TL;DR

Quick Example

Schema:

Server (GraphQL Yoga with a Redis-backed pub/sub):

Client (Apollo or urql with graphql-ws):

Core Concepts

How Subscriptions Execute

  1. The client sends a subscription operation over a persistent transport.
  2. The server validates it and calls the field's subscribe function, which returns an async iterator (a stream of events).
  3. For each event, the server runs the normal execution on the selection set, with resolve mapping the event to the field's value and nested resolvers filling in fields, then sends the result.
  4. The stream ends when the client unsubscribes, the connection closes, or the server completes it.

A subscription operation must select exactly one root field.

Transports

SSE is often easier to operate: it uses plain HTTP, reconnects automatically, and passes through proxies and load balancers designed for HTTP. WebSockets suit high-frequency, bidirectional scenarios.

Pub/Sub and Horizontal Scaling

In-memory pub/sub only reaches subscribers connected to the same process. With several server instances behind a load balancer, a mutation handled by instance A must notify subscribers on instances B and C. Use a shared broker:

Publish domain events (from mutations, background jobs, or change data capture) and let the GraphQL layer subscribe to them. That keeps real-time delivery decoupled from business logic.

Filtering and Authorization

Alternatives

GraphQL's own guidance: subscriptions are best for small incremental changes to large objects, or low-latency real-time updates. Otherwise, prefer polling.

Best Practices

Send Small Events, Let Clients Select Data

Publish a lightweight event (IDs plus what changed), and let the subscription's selection set resolve the fields each client needs, batched with DataLoader when many subscribers receive the same event.

Plan for Reconnection and Missed Events

Connections drop on mobile networks and deploys. With at-most-once pub/sub, events during a disconnect are lost. On reconnect, clients should refetch current state with a query, then resume the subscription. Use sequence numbers or timestamps if exact replay matters.

Limit Connections and Subscriptions

Cap subscriptions per connection and connections per user, and set idle timeouts and keep-alive pings. Every open subscription holds server memory. See GraphQL security.

Load-Balance Long-Lived Connections Carefully

Configure proxies for WebSocket upgrades or SSE (disable buffering, raise idle timeouts), and drain connections gracefully on deploy so clients reconnect smoothly rather than all at once.

Common Mistakes

In-Memory Pub/Sub in a Multi-Instance Deployment

Works locally with one process, then silently drops events in production behind a load balancer. Use Redis or another shared broker.

Broadcasting Everything and Filtering in Memory

Publishing every order change to one topic and filtering per subscriber in every instance wastes CPU at scale. Use targeted topics keyed by entity or tenant.

Skipping Per-Event Authorization

Checking permissions only when the subscription starts can leak data if the viewer's access is revoked, or if events include data from related objects the viewer can't see.

FAQ

Do GraphQL subscriptions require WebSockets?

No. graphql-ws over WebSockets is the most common transport, but GraphQL over Server-Sent Events and multipart HTTP responses are well-supported alternatives that work over ordinary HTTP and are often easier to operate.

How do subscriptions scale?

The GraphQL servers hold connections and execute selection sets; a shared pub/sub broker distributes events to every instance. Scale horizontally by adding server instances, use targeted topics to avoid wasted fan-out, and batch data loading for events delivered to many subscribers.

Should I use subscriptions or polling?

Polling is simpler and adequate for data that changes every few seconds or less often, or where slight staleness is fine. Use subscriptions when users need low-latency updates (chat, notifications, live tracking), or when polling would waste significant resources.

Can subscriptions work with federation?

Yes. Apollo Router and other federation gateways support subscriptions, routing each to the subgraph that owns the subscription field, over WebSockets or multipart HTTP. See GraphQL federation.

Related Topics

References