GraphQL Subscriptions and Realtime: Concepts, Practice, and the Magento Context
AI generated
{ }
type
GraphQL · Subscriptions · Realtime · WebSocket · Architecture
Subscriptions and Realtime
with GraphQL

GraphQL subscriptions enable realtime communication over persistent connections, but they come with substantial scaling and infrastructure requirements. This article explains the concept, the transport options, the design decisions, and when subscriptions are actually the right choice.

15 min read Subscriptions · WebSocket · SSE · Polling · Pub/Sub GraphQL · Node.js · Scaling · Magento

1. What GraphQL subscriptions mean conceptually

GraphQL subscriptions are the third operation type alongside queries and mutations. While a query reads data once and a mutation writes data once, a subscription opens a persistent connection between client and server. The server actively pushes data whenever a relevant event occurs, without the client having to ask again. The basic concept is comparable to an event listener: the client registers interest in certain events, and the server notifies it when they happen.

The schema model for subscriptions is declarative and looks similar to a query at first glance: you define which fields you want to receive. The difference lies in the transport protocol and the delivery model. While queries and mutations work over standard HTTP request-response, subscriptions need a long-lived bidirectional or unidirectional connection. This connection must be actively held open by the server process, which has significant implications for infrastructure and scaling.

2. Transport layers: WebSocket, SSE, and polling compared

The most common implementation of GraphQL subscriptions uses WebSockets. The graphql-ws protocol (the successor to the older subscriptions-transport-ws) standardizes the message formats for connection setup, subscription start, data transfer, and connection teardown over WebSocket. WebSockets are bidirectional: both client and server can send messages. Subscriptions technically only need the server-to-client direction, but the bidirectional nature also enables heartbeat mechanisms and flow control.

Server-Sent Events (SSE) are a lighter-weight alternative: a unidirectional HTTP connection over which the server pushes events to the client. SSE is simpler to implement, requires no dedicated WebSocket infrastructure, and works with standard HTTP/2 multiplexing. For many subscription scenarios, SSE is sufficient. Polling (regularly querying the server via a query) is the simplest method, but it scales poorly and generates unnecessary load even when nothing has changed. It is a workaround, not an architectural recommendation.

3. Subscription schema: design and patterns

Schema design for subscriptions follows the same principles as query and mutation design, but has a few peculiarities. Subscription fields should be defined granularly: instead of a generic dataChanged subscription that covers everything, specific subscriptions like orderStatusChanged, stockLevelUpdated, or chatMessageReceived are easier to maintain, easier to filter, and more efficient. Granular subscriptions let the server deliver events specifically to only the clients that are actually affected.

An important pattern is subscription filter arguments. A subscription orderStatusChanged(orderId: ID!) with a required argument lets the server scope the subscription to a specific record. Without filtering, every client would receive all order status updates for all customers, a serious performance and privacy violation. The filtering logic must be implemented server-side and should check, before delivery, whether the requesting client is authorized to receive this specific event.


# Subscription schema design: granular, filtered, documented
type Subscription {
  orderStatusChanged(orderId: ID!): OrderStatusEvent
    @doc(description: "Fires when the status of a specific order changes")

  stockLevelUpdated(sku: String!): StockUpdateEvent
    @doc(description: "Fires when stock quantity for a SKU changes")

  chatMessageReceived(conversationId: ID!): ChatMessage
    @doc(description: "New message in a specific customer support conversation")
}

type OrderStatusEvent {
  order_id: ID!
  old_status: String!
  new_status: String!
  updated_at: String!
}

type StockUpdateEvent {
  sku: String!
  quantity: Int!
  is_in_stock: Boolean!
}

4. Pub/Sub backend: the missing piece of the puzzle

GraphQL subscriptions need a Pub/Sub backend that mediates events between the part of the system that produces events (for example an order status update in the backend) and the subscription server that holds the persistent client connections. Without this middle piece, every server process would have to generate all events itself, which with multiple instances leads to the problem that a client is connected to instance A while the event is triggered on instance B.

Proven Pub/Sub backends for GraphQL: Redis with Pub/Sub functionality is the most common choice for medium-sized deployments. Redis lets you publish events on a channel and have them received by all subscribed server instances. For larger deployments and higher throughput requirements, Apache Kafka or Google Cloud Pub/Sub come into play. The subscription server receives events from the Pub/Sub system and forwards them to the matching connected clients, after filtering and an authorization check.


# Subscription flow: event triggers publication, server filters and pushes

# 1. Backend fires event (order status change):
#    Redis PUBLISH order:status:changed '{"orderId":"100000123","newStatus":"shipped"}'

# 2. Subscription server receives event from Redis
# 3. Server finds all clients subscribed to orderStatusChanged(orderId: "100000123")
# 4. Server checks authorization for each client
# 5. Server pushes filtered data to authorized clients

subscription WatchMyOrder {
  orderStatusChanged(orderId: "100000123") {
    order_id
    new_status
    updated_at
  }
}

# Client receives update automatically when status changes:
# { "data": { "orderStatusChanged": {
#     "order_id": "100000123",
#     "new_status": "shipped",
#     "updated_at": "2026-05-09T14:23:11Z"
# }}}

5. Scaling challenges with subscriptions

The biggest challenge in scaling GraphQL subscriptions: persistent connections tie up server resources permanently. An HTTP request for a query is finished after a few milliseconds. A WebSocket connection for a subscription can stay open for hours or days, and during that time it occupies a file descriptor, memory, and CPU capacity. 10,000 concurrent subscription connections mean 10,000 persistent connections that have to be held on the same or on distributed servers.

For high connection counts you need a subscription server with an event-loop architecture, typically Node.js with the graphql-ws package, or specialized services like Ably, Pusher, or AWS AppSync. PHP-based application servers such as Magento are structurally not suited to holding thousands of persistent WebSocket connections, because PHP traditionally works synchronously and request-bound. ReactPHP or Swoole offer asynchronous extensions, but they require substantial architectural adjustments and are rarely used in Magento projects.

6. Magento and subscriptions: the honest assessment

Magento GraphQL currently does not support native subscriptions. The framework is primarily built around synchronous HTTP request-response cycles, and the PHP architecture makes persistent WebSocket connections practically difficult. This is not a weakness of Magento but a consequence of design decisions optimized for high throughput on transactional storefront requests, not for persistent realtime communication.

In practice this means: when Magento projects need realtime features (live order tracking, stock level notifications, chat support), they use a separate service layer for the subscription infrastructure. This service receives events from Magento (via webhooks, message queues, or direct database change events) and forwards them to clients over WebSocket or SSE. The Magento GraphQL endpoint stays responsible for transactional queries and mutations, while a Node.js subscription server handles realtime communication.

7. Realtime alternatives without native subscriptions

For many realtime requirements, subscriptions are not the only or best solution. Smart polling (queries at short intervals with If-Modified-Since logic) can be sufficient for many use cases, without the infrastructure complexity of WebSockets. The advantage: standard HTTP, no persistent connection, easily cacheable. The disadvantage: higher latency and unnecessary requests when nothing has changed.

Server-Sent Events (SSE) are an excellent middle ground: simpler infrastructure than WebSocket, works over standard HTTP, automatic reconnecting in the browser. For many commerce realtime scenarios (order status updates, stock level alerts) SSE is entirely sufficient. Push notifications via Firebase or the Web Push API are suited to asynchronous notifications that get delivered even when the user is not actively on the page. The choice between these options depends on the required latency, infrastructure complexity, and the number of concurrent users.


# Alternative to subscriptions: smart polling with change detection
# Query with timestamp filter, only fetch if data changed

query OrderStatusSince($orderId: ID!, $since: String!) {
  orderStatusHistory(orderId: $orderId, changedSince: $since) {
    has_changes
    current_status
    history {
      status
      changed_at
      comment
    }
  }
}

# Client polls every 30 seconds, passes last-seen timestamp
# Server returns has_changes: false if nothing changed (lightweight)
# Only on change: server returns full data

8. Wrong / Right: when subscriptions make sense

Subscriptions make sense when low latency and high update frequency are required at the same time. Chat applications, live collaboration tools, realtime auctions, or live sports scores: here polling is too slow and SSE may be too one-directional. For commerce scenarios like order status updates, which change rarely, polling or SSE is almost always the better choice: simpler to implement, simpler to scale, and sufficient for the use case.

Method Latency Infrastructure Best Use Case
Polling High (interval-dependent) Standard HTTP Rarely changing data, simple setups
SSE Low (sub-second) HTTP, no WS infra Server push, notifications, status updates
WebSocket/Subscription Very low (ms) WS server + Pub/Sub Chat, collaboration, live auctions
Web Push Variable (minutes) Push service (Firebase etc.) Asynchronous notifications, even offline
Managed Services Low Outsourced (Ably, Pusher) Fast rollout without owning infrastructure

9. Realtime approaches compared

The most important design decision for realtime in GraphQL projects: always start with the simplest approach that meets the requirements. Subscriptions are powerful, but they significantly increase system complexity. Anyone who introduces WebSockets for order status updates on an e-commerce site is over-engineering the use case. Anyone who works with polling for a live chat feature is fighting structural limits. The right technology choice follows from the latency requirement, the update frequency, and the acceptable infrastructure complexity.

GraphQL Subscriptions and Realtime: The Essentials at a Glance

When Subscriptions

Low latency plus high update frequency at the same time: chat, collaboration, live auctions. Not for occasional status updates.

Transport

WebSocket (graphql-ws) for bidirectional use cases. SSE for simpler server-to-client pushing. Polling as a fallback.

Magento

No native subscriptions. Separate Node.js service plus Redis Pub/Sub for realtime, with Magento as the event source via message queue.

Scaling

Persistent connections tie up resources. Redis Pub/Sub for multi-instance deployments. Managed services for fast implementation.

10. Summary

GraphQL subscriptions are a powerful tool for realtime communication, but not a default tool for every project. The infrastructure requirements (WebSocket server, Pub/Sub backend, persistent connection management) only justify the effort when the use case genuinely needs low latency and high update frequency. For commerce scenarios like order status updates or stock level warnings, SSE or smart polling is the better choice in most cases.

In Magento projects, native subscriptions are not available, and routing through separate services is the common approach in practice. Anyone implementing realtime in Magento projects should start with the simplest approach that meets the requirements: polling first, then SSE, then WebSocket/subscriptions, weighing the added complexity against the added value at every step. The GraphQL subscription syntax is elegant; the infrastructure behind it is considerably less so.

11. FAQ: GraphQL Subscriptions and Realtime

1Difference between query and subscription?
Query: one-off request-response. Subscription: persistent connection, server actively sends data on events.
2Which protocol do subscriptions use?
By default WebSocket with graphql-ws. Alternatively SSE for simpler unidirectional scenarios.
3Why do subscriptions need Pub/Sub?
With multiple instances: events can be triggered on instance A while clients are connected to instance B. Redis mediates across instances.
4Does Magento support native subscriptions?
Not at the moment. Realtime in Magento is typically implemented via separate Node.js services with Redis.
5When is polling better than subscriptions?
When data changes rarely, simple infrastructure matters, and latency in the minute range is acceptable.
6What are Server-Sent Events?
HTTP connection for unidirectional server pushing. Simpler than WebSocket, works with HTTP/2, automatic reconnecting.
7How do you scale many WebSocket connections?
Redis Pub/Sub for cross-instance events. Event-loop server (Node.js). At very high counts: managed services like Ably.
8How do you filter events per client?
Subscription arguments (orderId: ID!). Server filters subscribed clients and checks each client's authorization on receiving an event.
9What is graphql-ws?
Recommended WebSocket protocol for GraphQL. Replaces subscriptions-transport-ws with better stability and active maintenance.
10What are managed subscription services?
Ably, Pusher, AWS AppSync: WebSocket infrastructure as a managed service. Reduces operational effort but creates vendor dependency.