SSE vs. WebSockets: diferenças e quando usar cada tecnologia
Compare SSE e WebSockets, entenda comunicação unidirecional e bidirecional, reconexão, escalabilidade e quando usar cada tecnologia.

Uma tela precisa mostrar o progresso de uma tarefa, receber notificações ou exibir a resposta de uma inteligência artificial enquanto ela é gerada. Surge então a dúvida: usar SSE vs. WebSockets?
As duas tecnologias mantêm comunicação contínua com o servidor, mas resolvem problemas diferentes.
Server-Sent Events é a escolha mais simples quando os dados fluem principalmente do servidor para o cliente.
WebSockets fazem sentido quando cliente e servidor precisam trocar mensagens a qualquer momento, com baixa latência e pelo mesmo canal.
Essa diferença de direção costuma ser mais importante que a popularidade de cada tecnologia.
Neste guia, você verá como cada opção funciona, exemplos em JavaScript, reconexão, autenticação, proxies, escalabilidade, backpressure e uma matriz prática para escolher sem complicar a arquitetura.
O que é SSE?
SSE significa Server-Sent Events, ou eventos enviados pelo servidor. O navegador abre uma requisição HTTP persistente, e o servidor mantém a resposta aberta para transmitir novos eventos sempre que houver informação disponível.
O fluxo é unidirecional: servidor para cliente. Caso o navegador precise enviar um comando, pode usar uma requisição HTTP normal.
Essa combinação funciona bem quando a aplicação recebe muitas atualizações, mas envia poucas ações.
O HTML Living Standard define Server-Sent Events e a interface EventSource. A conexão usa o tipo de conteúdo text/event-stream, e cada evento é descrito em linhas de texto UTF-8.
Como Server-Sent Events funciona
O cliente cria um EventSource apontando para uma URL. O servidor responde com os cabeçalhos corretos e não encerra a resposta. Cada mensagem termina com uma linha em branco:
id: tarefa-42-7
event: progresso
data: {"percentual":70}
datacontém o conteúdo entregue ao cliente.eventdefine um tipo de evento opcional.ididentifica a última mensagem processada.retrypode sugerir o intervalo de reconexão em milissegundos.- Linhas iniciadas por dois-pontos podem funcionar como comentários e manter a conexão ativa.
Se a conexão cair, EventSource tenta reconectar automaticamente. Quando existe um ID, o navegador pode enviar Last-Event-ID na nova requisição.
O servidor precisa armazenar ou reconstruir os eventos caso queira reenviar o que foi perdido; a API sozinha não cria esse histórico.
Exemplo de SSE no servidor e navegador
Este servidor Node.js mínimo cria um evento de progresso a cada segundo:
import http from "node:http";
http.createServer((req, res) => {
if (req.url !== "/eventos") {
res.writeHead(404).end();
return;
}
res.writeHead(200, {
"Content-Type": "text/event-stream; charset=utf-8",
"Cache-Control": "no-cache"
});
res.write("retry: 5000\n\n");
let percentual = 0;
const timer = setInterval(() => {
percentual += 10;
res.write(`id: ${percentual}\n`);
res.write("event: progresso\n");
res.write(`data: ${JSON.stringify({ percentual })}\n\n`);
if (percentual === 100) {
clearInterval(timer);
res.end();
}
}, 1000);
req.on("close", () => clearInterval(timer));
}).listen(3000);
No navegador, o consumo usa a API nativa:
const eventos = new EventSource("/eventos");
eventos.addEventListener("progresso", (evento) => {
const dados = JSON.parse(evento.data);
console.log(dados.percentual);
});
eventos.onerror = () => {
console.log("Conexão interrompida; o navegador tentará novamente.");
};
Em produção, valide autenticação, cancelamento, heartbeat, limite de fila e comportamento do proxy.
Quem está começando no servidor pode revisar quando usar Node.js no back-end antes de transformar o exemplo em uma aplicação completa.

O que é WebSocket?
WebSocket é um protocolo de comunicação bidirecional. Depois que a conexão é estabelecida, cliente e servidor podem enviar mensagens independentemente, sem iniciar uma nova requisição HTTP para cada troca.
O RFC 6455 define o protocolo WebSocket como um handshake inicial seguido por enquadramento de mensagens sobre uma conexão TCP.
A API usada por aplicações web é mantida no WebSockets Living Standard.
Ao contrário do SSE, WebSocket aceita mensagens de texto e binárias.
Ele é apropriado quando o cliente também precisa publicar eventos frequentes: movimento em um jogo, alterações colaborativas, áudio, telemetria de controle ou mensagens de chat.
Como WebSocket funciona
No cenário clássico sobre HTTP/1.1, o cliente inicia um handshake HTTP solicitando a mudança de protocolo.
Se o servidor aceitar, responde com o status apropriado e a comunicação passa a usar frames WebSocket. Aplicações públicas devem usar wss://, protegido por TLS.
A partir daí, a aplicação define seu próprio protocolo de mensagens. Um campo type, por exemplo, pode distinguir presença, chat e confirmação.
Também é preciso decidir formato, versionamento, correlação, autorização, erros, reenvio e ordem dos eventos.
WebSocket entrega um canal, não uma arquitetura pronta. Bibliotecas podem acrescentar salas, reconexão e fallback, mas essas funções não fazem parte automaticamente da interface básica do navegador.
Exemplo de WebSocket no navegador
const socket = new WebSocket("wss://api.exemplo.com/tempo-real");
socket.addEventListener("open", () => {
socket.send(JSON.stringify({
type: "entrar",
canal: "pedido-42"
}));
});
socket.addEventListener("message", (evento) => {
const mensagem = JSON.parse(evento.data);
console.log(mensagem);
});
socket.addEventListener("close", (evento) => {
console.log("Conexão encerrada", evento.code);
});
Uma implementação real deve validar cada mensagem e usar estados como CONNECTING, OPEN, CLOSING e CLOSED.
O cliente também precisa implementar reconexão com espera progressiva e variação aleatória para evitar que milhares de dispositivos retornem ao mesmo tempo.

SSE vs. WebSockets: comparação direta
| Critério | SSE | WebSockets |
|---|---|---|
| Direção | Servidor para cliente | Bidirecional |
| Base | Resposta HTTP persistente | Protocolo WebSocket após handshake |
| Formato nativo | Texto UTF-8 | Texto ou binário |
| API do navegador | EventSource | WebSocket |
| Reconexão | Automática na API nativa | Implementada pela aplicação |
| Retomada | Suporte a ID do último evento | Protocolo próprio |
| Envio do cliente | Outra requisição HTTP | No mesmo canal |
| Cabeçalhos personalizados no navegador | Limitados no EventSource nativo | Limitados no construtor nativo |
| Integração com infraestrutura HTTP | Geralmente mais simples, mas exige evitar buffering | Exige suporte ao upgrade ou mecanismo equivalente |
| Melhor encaixe | Feeds, progresso, notificações e streaming de texto | Chat intenso, colaboração, jogos e controle em tempo real |
Quando usar SSE
- Progresso de importações, relatórios e tarefas em segundo plano.
- Notificações e atualizações de status.
- Feeds de eventos, auditoria ou observabilidade.
- Painéis em que o servidor publica métricas periodicamente.
- Streaming de texto quando uma requisição GET é suficiente.
- Aplicações que desejam reconexão nativa e semântica de último evento.
SSE permite manter comandos em uma API REST e reservar o fluxo persistente apenas para atualizações.
Isso preserva logs, autorização e escalabilidade HTTP em operações comuns.
Quando usar WebSockets
- Chats com troca frequente, presença e digitação.
- Editores colaborativos e sincronização de cursores.
- Jogos multiplayer e atualizações rápidas de estado.
- Controle remoto, telemetria interativa e dispositivos.
- Transferência de mensagens binárias.
- Protocolos de aplicação em que ambos os lados publicam continuamente.
A frequência e a simetria importam. Se o usuário envia um comando ocasional e recebe centenas de atualizações, SSE mais HTTP pode continuar sendo a solução menor.
Se as duas direções carregam eventos contínuos, WebSocket reduz a necessidade de canais separados.
SSE em streaming de respostas de IA
Respostas de IA são frequentemente unidirecionais após o envio do prompt: o cliente envia a solicitação e o servidor devolve partes do texto.
O formato SSE é conveniente para separar eventos como início, fragmento, referência, erro e conclusão.
Há uma distinção importante. A API nativa EventSource abre uma requisição GET e não permite definir cabeçalhos arbitrários.
Se o prompt precisa seguir no corpo de um POST ou usar autorização personalizada, muitas implementações recorrem a fetch e leem um ReadableStream.
O servidor pode enviar um formato inspirado em SSE, mas o cliente está consumindo streaming de fetch, não um EventSource tradicional.
Nosso guia sobre streaming de respostas de IA no Next.js aprofunda o fluxo entre servidor e interface.
A decisão deve considerar cancelamento, tratamento de erro, moderação e o que acontece se a conexão cair no meio da geração.
Um chat precisa mesmo de WebSockets?
Nem sempre. Um chat de suporte com baixa frequência pode enviar mensagens por POST e receber novas mensagens por SSE.
Essa separação simplifica o servidor e mantém cada envio como uma operação HTTP observável.
WebSocket se torna atraente quando o produto inclui presença, indicador de digitação, confirmação rápida, múltiplas salas, chamadas frequentes e outros eventos nos dois sentidos.
Mesmo assim, documente o protocolo e não misture mensagens sem versionamento.
Reconexão e garantia de entrega
Conexões caem quando o dispositivo troca de rede, o navegador suspende a aba, um proxy encerra ociosidade ou uma implantação reinicia o servidor. Projetar reconexão não é opcional.
SSE tenta reconectar automaticamente e oferece o último ID como ponto de retomada.
Para isso funcionar, o servidor precisa manter um log de eventos por algum período e decidir o que fazer quando o ID já expirou: enviar um estado completo, recomeçar ou informar que a sincronização precisa ser refeita.
Em WebSocket, defina espera progressiva, jitter, heartbeat e ressincronização.
Depois de reconectar, o cliente não deve presumir que recebeu tudo. Pode enviar a última versão conhecida ou solicitar um snapshot.
Nenhuma das tecnologias garante exatamente uma entrega por conta própria; duplicação e idempotência pertencem ao protocolo da aplicação.
Proxies, timeouts e infraestrutura
Uma aplicação funcionar em localhost não prova que funcionará atrás de CDN, gateway e balanceador.
Para SSE, desative buffering da resposta onde necessário, envie cabeçalhos adequados e use heartbeats em intervalos compatíveis com o timeout de ociosidade.
Compressão também deve ser testada, pois pode acumular dados antes de liberá-los.
Com WebSocket, confirme suporte ao handshake, duração máxima, drenagem de conexões durante deploy e encaminhamento de frames.
O NGINX como proxy reverso, por exemplo, precisa ser configurado de acordo com a tecnologia e os limites da plataforma.
A documentação da MDN sobre SSE observa que conexões sobre HTTP/1.1 podem esbarrar no limite baixo de conexões simultâneas por navegador e domínio.
Com HTTP/2, o número de streams é negociado, reduzindo esse problema. Ainda assim, evite abrir um fluxo por componente: prefira uma conexão por aplicação e distribua eventos internamente.
Como escalar conexões persistentes
Milhares de conexões abertas consomem descritores, memória e capacidade de rede, mesmo quando quase não transmitem dados.
Meça conexões por instância, bytes por segundo, duração, filas, desconexões e tempo de reconexão.
- Separar produção e entrega: serviços de negócio publicam eventos em um broker; gateways mantêm conexões com clientes.
- Evitar estado local indispensável: qualquer instância deve reconstruir a assinatura ou consultar um armazenamento compartilhado.
- Planejar deploy: retirar a instância do balanceador, drenar conexões e orientar reconexão.
- Controlar fan-out: agrupar assinantes e não repetir consultas caras para cada conexão.
- Limitar o cliente: aplicar cotas por usuário, organização, IP e canal.
Em arquiteturas de microsserviços, não faça cada serviço abrir conexões públicas. Um gateway de tempo real pode autenticar clientes, gerenciar assinaturas e consumir eventos internos.
Backpressure e clientes lentos
Backpressure é a capacidade de reagir quando o produtor envia dados mais rápido do que o consumidor processa.
Sem controle, filas crescem, memória aumenta e mensagens ficam obsoletas.
A documentação da API WebSocket na MDN alerta que a interface tradicional não oferece backpressure automático para mensagens recebidas.
No envio, bufferedAmount ajuda a observar quantos bytes ainda aguardam transmissão, mas a aplicação precisa definir limites e políticas.
- Descarte estados intermediários quando apenas o valor mais novo importa.
- Agrupe métricas em janelas em vez de enviar cada alteração.
- Pause ou desconecte clientes que excedam filas seguras.
- Separe eventos críticos de atualizações descartáveis.
- Limite tamanho e frequência das mensagens em ambas as direções.
Segurança e autenticação
Use HTTPS e WSS. Autentique a abertura da conexão, autorize cada assinatura e reavalie permissões quando o usuário muda de canal.
Uma conexão autenticada não concede acesso automático a todo evento.
- Valide
Origine configure CORS de forma explícita para SSE entre origens. - Evite tokens duradouros na query string, pois URLs podem aparecer em logs e históricos.
- Se usar cookies, considere CSRF,
SameSite, origem e escopo da sessão. - Defina expiração, renovação e revogação sem depender de uma conexão eterna.
- Valide esquema, tamanho e frequência de cada mensagem WebSocket.
- Não envie segredos para canais que o cliente não está autorizado a acompanhar.
As mesmas boas práticas para APIs seguras e escaláveis continuam válidas: menor privilégio, limites, registros de auditoria, validação de entrada e tratamento previsível de erros.
Checklist para tomar a decisão
- Mapeie a direção: o cliente publica eventos continuamente ou apenas recebe?
- Defina o formato: texto é suficiente ou existe conteúdo binário?
- Classifique a frequência: quantas mensagens cada lado envia por segundo?
- Desenhe a retomada: como recuperar estado após uma queda?
- Teste a infraestrutura: CDN, proxy, balanceador e plataforma aceitam a duração desejada?
- Modele segurança: como autenticar, autorizar canais e revogar acesso?
- Planeje clientes lentos: qual é o limite da fila e o que pode ser descartado?
- Meça uma solução simples: compare SSE, WebSocket e polling com carga representativa.
Se os eventos são unidirecionais, textuais e toleram o modelo HTTP, comece por SSE.
Se a interação é genuinamente bidirecional e frequente, escolha WebSocket.
Quando o requisito ainda é incerto, polling com intervalo moderado pode ser a linha de base mais barata.
Perguntas frequentes
SSE é realmente comunicação em tempo real?
Sim, no sentido de entregar atualizações assim que o servidor as disponibiliza por uma conexão aberta. A latência real depende da aplicação, rede, buffering, proxy e frequência de envio.
SSE consegue enviar dados binários?
Não de forma nativa. O formato é texto UTF-8. É possível codificar bytes em texto, mas isso aumenta tamanho e processamento. Para fluxo binário frequente, WebSocket ou outra tecnologia tende a ser mais adequada.
WebSocket é sempre mais rápido que SSE?
Não. WebSocket tem frames compactos e comunicação bidirecional, mas a latência percebida depende do volume, frequência, infraestrutura e processamento. Para atualizações textuais em uma direção, SSE pode atender com menor complexidade.
É possível abrir EventSource com POST?
Não com a interface EventSource nativa, que usa GET. Para iniciar o fluxo com POST e corpo de requisição, use streaming com fetch ou crie o recurso por POST e abra depois uma URL SSE por GET.
SSE e WebSockets podem coexistir no mesmo sistema?
Sim. Um produto pode usar SSE para notificações e progresso, enquanto reserva WebSockets para colaboração ou chat intenso. A escolha pode ser feita por caso de uso, não por aplicação inteira.
Quando polling ainda é suficiente?
Polling é suficiente quando atualizações são pouco frequentes, alguns segundos de atraso são aceitáveis e a simplicidade vale mais que manter conexões abertas.
Ele também serve como linha de base para medir se tempo real acrescenta valor.
Conclusão
A escolha entre SSE vs. WebSockets começa pela direção da conversa. SSE entrega eventos textuais do servidor para o cliente usando uma resposta HTTP persistente, com reconexão nativa e semântica de último evento.
WebSocket mantém um canal bidirecional para mensagens de texto ou binárias, mas exige que a aplicação defina reconexão, retomada e protocolo.
Não use WebSocket apenas porque o produto “tem tempo real”. Para notificações, progresso, feeds e muitos streamings de texto, SSE costuma ser suficiente.
Use WebSocket quando ambos os lados realmente enviam eventos frequentes.
Em qualquer escolha, teste quedas, proxies, clientes lentos, deploys e permissões: são esses detalhes que transformam uma demonstração em um sistema confiável.