Join us for GraphQL Summit, October 10-12 in San Diego. Use promo code ODYSSEY for $400 off your pass.
Launch GraphOS Studio

Multipart HTTP protocol for GraphQL subscriptions

For GraphQL clients communicating with the Apollo Router

To execute GraphQL subscription s on the Apollo , client apps do not communicate over WebSocket. Instead, they use HTTP with multipart responses. This multipart protocol is built on the same Incremental Delivery over HTTP spec that the Apollo uses to support the @defer directive.

You only need to read this reference if you're adding protocol support to a new GraphQL client library! Apollo Client for Web, Kotlin, and iOS all support this protocol.

Executing a subscription

To execute a subscription on the Apollo , a GraphQL client sends an HTTP request with almost the exact same format that it uses for query and requests.

The only difference is that the request should include the following Accept header:

Example header
Accept: multipart/mixed; boundary="graphql"; subscriptionSpec="1.0", application/json

At this time, the value for boundary should always be graphql, and the value for subscriptionSpec should always be 1.0.

As subscription events occur, the sends back HTTP response "parts" that conform to the definition of multipart content specified in RFC1341.

An example response might look like this:

Content-Type: application/json
Content-Type: application/json
{"payload": {"data": { "newPost": { "id": 123, "title": "Hello!"}}}}
  • If the request uses HTTP/1, the response includes the Transfer-Encoding: chunked header.
  • If the request uses HTTP/2 (which provides built-in support for data streaming), chunked encoding is not used (and is in fact disallowed).


While a client subscription remains active, the Apollo sends periodic "heartbeat" response parts to prevent any intermediaries from closing the connection. The body of a heartbeat is an empty JSON object, which clients should ignore silently:

Heartbeat response part
Content-Type: application/json

Message and error format

This protocol differentiates between transport-level errors and GraphQL errors in response payloads themselves. This is because the GraphQL response format is defined in the GraphQL spec, and unexpected s might be confusing or could even break client typing.

With the exception of heartbeats, every response part body includes a payload property, which contains standard GraphQL response properties. The payload property can be null if a transport-level error occurs.

If a GraphQL-level error occurs, the Apollo can sometimes still return partial data, and the subscription connection should remain open. These errors are provided within the payload property:

"payload": {
"errors": [...],
"data": {...},
"extensions": {...}

If a fatal transport-level error occurs, the sends a message with a top-level errors and null payload , then closes the connection:

"payload": null,
"errors": [...]

Both types of errors follow the GraphQL error format, but top-level errors never include locations or path.

Subgraph protocol: HTTP callback
GraphOS reporting
Edit on GitHubEditForumsDiscord