GraphQL Subscriptions vs. WebSockets: o que está sendo comparado, afinal?

Atualizado em: agosto de 2026

Uma GraphQL subscription é um stream de eventos tipado e definido pelo schema; um WebSocket é o transporte cru sobre o qual ela costuma rodar. O “vs.” do título é uma confusão de camadas que vale desfazer antes de qualquer decisão: subscriptions não são uma alternativa a WebSockets — são uma das coisas que você pode rodar sobre um, do jeito que o HTTP roda sobre TCP. A escolha real é entre um protocolo tipado que alguém já especificou e um cano cru cujo protocolo você inventa.

Principais pontos

PerguntaResposta
WebSocketUm cano de bytes persistente e full-duplex — sem semântica de mensagem inclusa
GraphQL subscriptionUm stream de eventos definido pelo schema, tipado e validado como qualquer resposta GraphQL
A relação entre elesCamadas, não rivais — subscriptions rodam sobre WebSockets (ou SSE) via um sub-protocolo
O sub-protocolographql-ws: handshake init/ack, ids multiplexam operações, frames next/complete
A decisão de verdadeProtocolo tipado de prateleira vs. socket cru mais um protocolo que agora é seu

As camadas, em código

O que uma subscription realmente é no fio — uma conversa graphql-ws dentro de um WebSocket:

// cliente → servidor, depois que o socket abre
{ "type": "connection_init", "payload": { "authToken": "…" } }
// servidor → cliente
{ "type": "connection_ack" }
// o cliente inicia uma operação — o id multiplexa esta subscription
{ "type": "subscribe", "id": "1", "payload": {
    "query": "subscription { orderUpdated(status: PREPARING) { id status eta } }" } }
// o servidor transmite eventos tipados, um frame por ocorrência
{ "type": "next", "id": "1", "payload": { "data": { "orderUpdated": { "id": "o42", "status": "READY", "eta": null } } } }
// qualquer um dos lados encerra o stream
{ "type": "complete", "id": "1" }

E o que a maior parte do código de aplicação de fato escreve — uma subscription tipada com a pilha inteira gerenciada:

// JavaScript — Back4app JS SDK
// A typed subscription over a managed WebSocket fleet: the protocol,
// reconnects, and fan-out are the platform's problem, not yours
const orders = new Parse.Query('Order');
orders.equalTo('status', 'preparing');

const sub = await orders.subscribe();
sub.on('create', (o) => addCard(o));      // typed event, full object
sub.on('update', (o) => refreshCard(o));
sub.on('leave',  (o) => removeCard(o));   // edited out of the result set

sub.on('close', () => showOfflineBadge()); // socket lifecycle surfaced

Uma pilha, três camadas

GraphQL subscriptions em camadas sobre um transporte WebSocketO código de aplicação consome eventos tipados. Abaixo dele, um protocolo de subscription como o graphql-ws cuida do handshake, da multiplexação e do ciclo de vida do stream. Abaixo disso, a camada de transporte é normalmente um WebSocket e às vezes Server-Sent Events. O transporte move bytes; o protocolo dá significado a eles; o schema dá tipos.

Código de aplicação
eventos tipados, payloads no formato do schema

Protocolo de subscription — graphql-ws
connection_init/ack · subscribe · next · complete

Transporte — normalmente WebSocket, às vezes SSE
conexão persistente, entrega ordenada

TCP/IP

O código de aplicação consome eventos tipados. Abaixo dele, um protocolo de subscription como o graphql-ws cuida do handshake, da multiplexação e do ciclo de vida do stream. Abaixo disso, a camada de transporte é normalmente um WebSocket e às vezes Server-Sent Events. O transporte move bytes; o protocolo dá significado a eles; o schema dá tipos.

A camada WebSocket (RFC 6455) promete exatamente isto: um stream persistente, full-duplex e ordenado de frames de texto ou binários, acessível de qualquer navegador por uma API pequena. Ela não diz nada sobre o que uma mensagem significa — sem correlação requisição/resposta, sem convenção de autenticação, sem sinalização de erro, sem jeito de rodar dois streams lógicos em um socket. Todo projeto de socket cru redecide tudo isso.

A camada de subscription é precisamente esse conjunto de decisões faltantes, padronizado: connection_init/connection_ack carrega a autenticação; ids por operação multiplexam muitas subscriptions em um socket; frames next entregam payloads que são respostas GraphQL comuns — tipadas pelo schema, validadas, introspectáveis, consumidas pela mesma maquinaria de cliente que queries e mutations; complete encerra um stream sem matar os vizinhos. Uma nota histórica importa na prática: um sub-protocolo mais antigo do início do ecossistema ainda está em produção, e um cliente falando um com um servidor falando o outro falha de formas silenciosas e confusas — fixe o sub-protocolo explicitamente nas duas pontas.

E porque o contrato é de mensagens, não de sockets, o transporte por baixo é trocável — a mesma semântica de subscription roda cada vez mais sobre Server-Sent Events, o que combina com o formato esmagadoramente unidirecional do tráfego de subscription e herda a tolerância a proxies e a reconexão automática do SSE. “Subscriptions vs. WebSockets” se dissolve ao toque: uma é contrato, o outro é carregador.

GraphQL subscriptions vs. WebSockets crus

GraphQL subscriptionsWebSockets crus
CamadaProtocolo + sistema de tipos sobre um transporteO transporte em si
Contrato de mensagemDefinido pelo schema, validado, introspectávelO que você inventar e documentar
MultiplexaçãoEmbutida — ids por operação em um socketPor sua conta
Handshake de autenticaçãoPadronizado (payload do connection_init)Por sua conta
PayloadsJSON, no formato do schemaTexto e binário, qualquer formato
FiltragemArgumentos no campo da subscriptionCódigo de servidor que você escreve
Overhead por eventoEnvelope JSON + execução de resolver~2–14 bytes de framing
EcossistemaClientes GraphQL, codegen, ferramentalBibliotecas de socket cru
Melhor quandoOs eventos são dados de API tipados em um app GraphQLBinário, alta frequência ou semântica própria

Quando sockets crus ganham das subscriptions tipadas

Os casos honestos existem, só que são mais estreitos do que o entusiasmo por socket cru sugere. Payloads binários — pedaços de áudio, protocol buffers, estado de jogo — trafegam nativamente em frames WebSocket, mas precisariam ser codificados dentro de um envelope JSON de subscription. Taxa de mensagens — a milhares de eventos por segundo por cliente, a execução de resolver e o envelope JSON por evento deixam de ser ruído; um formato de frame compacto e próprio é otimização legítima. Semântica própria — backpressure, acks do cliente, codificação de deltas, cursores retomáveis — pertence a protocolos que você projeta, e enfiá-los nos frames de subscription briga com a spec. E não ter GraphQL para começar — adotar schema, resolvers e ferramental de cliente para ter eventos tipados é o rabo abanando o cachorro; um socket cru com formato de mensagem documentado é menor. A armadilha corre no sentido inverso também: times que escolhem sockets crus para eventos de API tipados e no formato JSON acabam escrevendo à mão multiplexação, handshake de autenticação e semântica de reconexão — um graphql-ws pior, um time incompatível por vez.

Casos de uso comuns

  • Streams de pedido e status — “me avise quando este pedido mudar”: dados de API tipados, taxa baixa, o ponto ideal das subscriptions.
  • Presença e comentários colaborativos — subscriptions em apps GraphQL que já são donos do schema; os eventos são só mais schema.
  • Cotações financeiras e dashboards — subscriptions enquanto os payloads seguem no formato JSON; sockets crus quando a taxa de ticks exige frames compactos.
  • Chat — qualquer uma das camadas funciona; o voto de minerva costuma ser se o app é GraphQL-first, já que as live queries cobrem o mesmo terreno sem fiação de eventos.
  • Estado multiplayer e mídia — binário, alta frequência, sensível a latência: território de WebSocket cru, protocolo e tudo.

Você deveria usar GraphQL subscriptions ou WebSockets crus? Matriz de decisão

Sua situaçãoUse
O app já fala GraphQL; os eventos são dados de API tipadosGraphQL subscriptions
Frames binários, ou milhares de eventos/s por clienteWebSockets crus
Você precisa de semântica própria — acks, deltas, cursores, backpressureWebSockets crus, com o protocolo documentado
Nenhum investimento em GraphQL, feed de eventos simplesSocket cru com um pequeno protocolo de frames — ou SSE
Os eventos são “os resultados desta consulta mudaram”Uma camada de live query — sem fiação de eventos nenhuma
Proxies rígidos, infraestrutura só HTTPSubscriptions sobre SSE
Time pequeno, sem apetite para ser dono de protocoloSubscriptions tipadas em um backend gerenciado

Limitações e trade-offs

  • Subscriptions herdam a operação de WebSockets. Empilhar camadas acrescenta significado, não mágica: estado de conexão, roteamento com afinidade, heartbeats e um backplane de pub/sub entre servidores continuam sendo a realidade de deploy por baixo.
  • Reconexão ainda perde eventos. O graphql-ws define streams, não retomada: um socket que cai significa frames perdidos, e a atualização (reconsultar e depois reinscrever) é lógica de aplicação nas duas pilhas.
  • Resolução por assinante custa. Subscriptions filtradas podem executar trabalho de resolver e de permissão por evento e por assinante — um tópico quente com milhares de ouvintes multiplica isso; projete filtros no servidor e estreitos.
  • Circulam dois sub-protocolos. Os protocolos legado e moderno de GraphQL sobre WebSocket são mutuamente ininteligíveis; pontas desencontradas falham em silêncio. Fixe as versões explicitamente.
  • Envelopes tipados cobram throughput. Serialização JSON e validação de schema por evento são invisíveis a dezenas de eventos por segundo e dominantes a milhares — meça antes de assumir qualquer coisa.

GraphQL subscriptions e WebSockets no Back4app

O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. O empilhamento descrito neste artigo mapeia direto na plataforma: a API GraphQL gerada automaticamente cobre as camadas de query e mutation a partir do seu schema, sem nenhum código de resolver, enquanto a camada de tempo real chega como Live Queries — eventos de subscription tipados e verificados por ACL sobre uma frota gerenciada de WebSockets, usando o protocolo aberto LiveQuery no lugar do graphql-ws e disparando por mudança no conjunto de resultados em vez de eventos conectados à mão. Você fica com a coluna do protocolo tipado da tabela comparativa — multiplexação, autenticação e tratamento de reconexão inclusos — sem operar a frota de sockets nem ser dono de uma especificação de protocolo.

Perguntas frequentes

GraphQL subscriptions e WebSockets são a mesma coisa?

Não — elas vivem em camadas diferentes. Um WebSocket é transporte: um cano de bytes persistente e full-duplex, sem opinião sobre o que trafega por ele. Uma GraphQL subscription é protocolo e contrato por cima: uma operação definida no schema cujos eventos chegam tipados, validados e no mesmo formato de qualquer outra resposta GraphQL. Comparar as duas diretamente é comparar uma estrada com uma linha de ônibus.

Qual protocolo as GraphQL subscriptions usam?

Normalmente o graphql-ws, o sub-protocolo moderno de GraphQL sobre WebSocket: o cliente abre o socket, envia connection_init, recebe connection_ack e então inicia operações com mensagens subscribe; o servidor transmite payloads next por id de subscription e qualquer um dos lados encerra com complete. Um sub-protocolo mais antigo do início do ecossistema ainda circula, e é por isso que cliente e servidor precisam concordar sobre qual dos dois falam.

GraphQL subscriptions podem rodar sobre Server-Sent Events?

Podem — o contrato de subscription é agnóstico de transporte, e SSE é um carregador legítimo, cada vez mais popular. Como o tráfego de subscription é esmagadoramente do servidor para o cliente, um stream HTTP unidirecional encaixa naturalmente, mantém proxies comuns e a semântica HTTP satisfeitos e traz reconexão automática de graça. WebSockets seguem como padrão na maior parte do ferramental, mas "subscriptions exigem WebSockets" é folclore, não fato.

Quando usar WebSockets crus em vez de GraphQL subscriptions?

Quando o tráfego deixa de parecer evento de API tipado: frames binários (áudio, estado de jogo, streams de sensores), taxas de mensagem muito altas em que validar schema e envelopar em JSON por evento custam throughput real, ou protocolos que precisam de semântica própria — cursores, deltas, acknowledgments — que brigam com o formato de subscription. Se você ainda não investiu em um schema GraphQL, o socket cru também evita importar um só por causa dos eventos.

GraphQL subscriptions escalam?

O transporte escala como qualquer frota de WebSockets — estado de conexão, roteamento com afinidade e um backplane de pub/sub entre servidores. A camada de subscription acrescenta um eixo próprio: cada evento pode ser resolvido e filtrado por assinante, então um tópico quente com muitos assinantes multiplica o trabalho dos resolvers. Plataformas gerenciadas absorvem a frota; o design do schema e a disciplina de filtro por assinante continuam sendo seus.

GraphQL subscriptions são a mesma coisa que live queries?

Primas próximas, com gatilhos diferentes. Subscriptions disparam em eventos nomeados que você conecta explicitamente — uma mutation publica, os assinantes recebem. Live queries disparam quando o conjunto de resultados de uma consulta muda — sem fiação de eventos, todo caminho de escrita coberto automaticamente. As duas costumam rodar sobre WebSockets. Uma camada de live query troca o design de eventos guiado por schema pela detecção automática de mudanças nos próprios dados.

Por que subscriptions precisam de um sub-protocolo?

Porque um WebSocket puro é só bytes ordenados. No momento em que duas partes precisam multiplexar várias subscriptions em um socket, correlacionar eventos com operações, negociar autenticação, sinalizar erros e encerrar streams com limpeza, elas precisam de framing de mensagens e regras — que todo time já inventou mal, uma versão incompatível por vez. O graphql-ws padroniza exatamente essa camada para que clientes e servidores interoperem.

Termos relacionados

Compare com

Leitura adicional

Pronto para construir seu backend?

Comece seu projeto no Back4app em minutos — banco de dados, autenticação, APIs e Cloud Code incluídos. Sem cartão de crédito.

Escrito e revisado por Back4app Engineering, Back4app Engineering · Publicado em 2026-08-25