[Jens Neuse](/content/people/jens-neuse/index.html)  
CEO & Co-Founder at WunderGraph  
April 25, 2022·10min read  
Last updated on September 9, 2025

**Editor's Note:** While this post provides great insights and mainly focuses on our product WunderGraph SDK, we’d like to introduce you to [WunderGraph Cosmo](/content/site-root.html).

As our main offering, Cosmo is designed to revolutionize API and GraphQL management. If you are exploring a GraphQL Federation solution, [take a look at the key features of WunderGraph Cosmo](/content/cosmo/features/index.html) to see how it can streamline and enhance your API workflows.

WunderGraph Cosmo is the complete solution for GraphQL Federation, providing a powerful and streamlined alternative to Apollo. Cosmo empowers teams to seamlessly compose, govern, and extend APIs across distributed microservices, enhancing performance, security, and scalability. By simplifying the complexities of managing federated architectures, Cosmo enables enterprises to focus on innovation and scaling with unmatched efficiency and ease.

## State of GraphQL Federation 2026  
How are teams governing schema changes, handling production traffic, and measuring Federation success? Share your experience and get early access to the full report. For every valid survey completed, we'll donate $30 to [UNICEF](https://www.unicef.org/).

[Take the Survey](https://8bxwlo3ot55.typeform.com/to/zIJKRQUe)

WunderGraph exposes GraphQL Subscriptions over SSE (Server-Sent Events) or Fetch (as a fallback). This post explains why we've decided to take this approach and think it's better than using WebSockets.

## What is a GraphQL Subscription?

GraphQL Subscriptions allow a client to subscribe to changes. Instead of polling for changes, the client can receive updates in real-time.

Here's a simple example from our [GraphQL Federation Demo](https://github.com/wundergraph/wundergraph-demo):

1. This is based on Apollo Federation. Once the "product" microservice has a price update, WunderGraph joins the data with the reviews from the "review" microservice, does an additional join with some user information from the "user" microservice, and sends the data back to the client.
2. The client gets this as a stream of data. This way, the user interface can be updated in real-time.

## Traditional ways of implementing GraphQL Subscriptions

The most widely adopted way of implementing GraphQL Subscriptions is to use WebSockets. The WebSocket API is an HTTP 1.1 standard that's usually supported by all modern browsers. (According to caniuse.com, [94.22% of all browsers support the WebSockets API](https://caniuse.com/?search=websocket))

First, the client sends an HTTP Upgrade request, asking the server to upgrade the connection to a WebSocket. Once the server upgrades the connection, both the client and the server can send and receive data by passing messages over the WebSocket.

### Problems with WebSockets

#### The WebSocket API is an HTTP 1.1 standard

Most websites nowadays use HTTP/2 or even HTTP/3 to speed up the web. HTTP/2 allows for multiplexing multiple requests over a single TCP connection. This means that the client can send multiple requests at the same time. HTTP/3 improves this even further.

What's problematic is that if your website is mixing both HTTP/1.1 and HTTP/2, the client will have to open multiple TCP connections to the server.

Clients can easily multiplex up to 100 HTTP/2 requests over a single TCP connection, whereas with WebSockets, you're forced to open a new TCP connection for each WebSocket.

### WebSockets are stateful

Another problem with WebSockets is that the client and the server have to keep track of the state of the connection. If we look at the principles of REST, one of them states that [requests should be stateless](https://restfulapi.net/statelessness/).

Stateless in this context means that each request should contain all the required information to be able to process it.

### Examples of using GraphQL Subscriptions with WebSockets

1. **Send an Authorization header with the Upgrade Request:** Each WebSocket connection starts with an HTTP Upgrade request. However, this approach is not very practical as it relies on previously sent headers.
2. **Send an Auth Token with the "connection_init" WebSocket Message:** While this can be practical, it also creates statefulness and could lead to security issues.
3. **Send an Auth Token with the "subscribe" WebSocket Message:** This may seem practical, but it poses security risks and is inefficient.

### WebSockets allow for bidirectional communication

This is not necessary for GraphQL Subscriptions and can lead to issues with server load.

### WebSockets are not ideal for SSR

Server-Side Rendering with WebSockets poses challenges as connections have to be established before rendering can begin.

## Summary of the Problems with GraphQL Subscriptions over WebSockets

- WebSockets make your GraphQL Subscriptions stateful
- WebSockets lead to performance issues
- WebSockets create security risks by exposing Auth Tokens to the client
- WebSockets allow for unnecessary bidirectional communication
- WebSockets complicate Server-Side Rendering (SSR)

## Why we chose SSE (Server-Sent Events) / Fetch to implement GraphQL Subscriptions

SSE and Fetch are stateless APIs, straightforward to use, and can be secured easily. Both APIs can leverage HTTP/2, enhancing performance.

### Advantages of SSE/Fetch

- **Stateless:** All necessary information is transmitted in each request, making the process simple and secure.
- **Secure:** Through the implementation of the "Token Handler Pattern", tokens are managed server-side, minimizing exposure.
- **No Bidirectional Communication:** Clients cannot send arbitrary data back to the server.
- **SSR Compatibility:** Fetch allows for easy implementation of Server-Side Rendering for GraphQL Subscriptions.

## Conclusion

Implementing GraphQL Subscriptions with SSE/Fetch offers a modern and effective solution to overcome the limitations associated with WebSockets.
