Como criar um chat em tempo real na Vercel com WebSockets?
Monte um chat de demonstração com Next.js, Node.js e WebSockets, teste a conexão localmente e entenda quando Redis é necessário para compartilhar mensagens entre instâncias.

O que vamos construir e para quem serve
Neste projeto, vamos montar um chat simples de demonstração com Next.js e WebSockets e publicá-lo na Vercel. O navegador mantém uma conexão aberta com o servidor, envia uma mensagem sem criar uma nova requisição HTTP para cada ação e recebe as mensagens em tempo real.
O projeto é para quem já conhece o básico de JavaScript e quer entender comunicação bidirecional na prática. A Vercel anunciou a disponibilidade geral de WebSockets nas Functions em 20 de outubro de 2026. Isso permite hospedar o endpoint junto da aplicação, mas não elimina limites de duração nem cria um banco de dados compartilhado automaticamente.
O exemplo abaixo mantém os sockets em memória e serve para aprender e validar o fluxo. Em produção, instâncias diferentes precisam compartilhar mensagens e estado por um serviço como Redis. A documentação oficial da Vercel usa esse padrão no tutorial completo de chat.
No final, você terá um chat funcional para testar conexões; também vai saber exatamente o que falta antes de torná-lo um serviço público.
Como a conexão funciona
Uma conexão WebSocket começa como uma requisição HTTP que pede uma troca de protocolo. Quando o servidor aceita a troca, cliente e servidor podem enviar mensagens pela mesma conexão. Isso é útil para chats, presença, cursores colaborativos e jogos simples. Para uma resposta de IA que só flui do servidor para o navegador, Server-Sent Events pode ser mais simples; WebSocket faz sentido quando os dois lados enviam mensagens continuamente.
Na Vercel, a conexão fica ligada à Function que a aceitou durante sua vida. Uma conexão nova pode cair em outra instância. Por isso, um conjunto de sockets mantido em uma variável local não é um mecanismo de publicação e assinatura global.
Passo 1: crie o aplicativo Next.js
Instale Node.js e pnpm ou use npm. No terminal, gere um projeto novo. Neste exemplo, escolhemos JavaScript para deixar os arquivos iniciais mais fáceis de acompanhar:
pnpm create next-app@latest chat-websocket-vercel --js --app
cd chat-websocket-vercel
pnpm add @vercel/functionsSe você usa npm, troque pnpm create por npx create-next-app@latest e pnpm add por npm install. Aceite a opção App Router se o assistente perguntar. A dependência @vercel/functions fornece a função de upgrade de conexão usada pelo exemplo de Next.js da Vercel.
Passo 2: crie o endpoint WebSocket
Dentro de app, crie as pastas api/ws e o arquivo route.js. O endpoint aceita a conexão, registra o socket em um conjunto local e retransmite cada mensagem para os clientes que estão na mesma instância:
import { experimental_upgradeWebSocket } from '@vercel/functions';
const clients = new Set();
export function GET() {
return experimental_upgradeWebSocket((socket) => {
clients.add(socket);
socket.on('message', (data) => {
const text = data.toString().trim();
if (!text || text.length > 500) return;
const message = JSON.stringify({ text, sentAt: new Date().toISOString() });
for (const client of clients) {
if (client.readyState === 1) client.send(message);
}
});
const remove = () => clients.delete(socket);
socket.on('close', remove);
socket.on('error', remove);
});
}O limite de 500 caracteres é apenas uma proteção simples para o exercício, não substitui controle de frequência nem validação de identidade. O conjunto clients existe na memória do processo. Ele desaparece quando a instância é reciclada e não pode entregar a mensagem a um socket conectado em outra instância.
Passo 3: conecte a interface do navegador
Substitua o conteúdo de app/page.js por uma tela básica. Ela abre a conexão ao carregar, mostra o status e envia o texto digitado quando a pessoa aperta o botão:
'use client';
import { useEffect, useRef, useState } from 'react';
export default function Home() {
const socketRef = useRef(null);
const [status, setStatus] = useState('conectando');
const [draft, setDraft] = useState('');
const [messages, setMessages] = useState([]);
useEffect(() => {
const scheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const socket = new WebSocket(scheme + '//' + window.location.host + '/api/ws');
socketRef.current = socket;
socket.onopen = () => setStatus('conectado');
socket.onclose = () => setStatus('desconectado');
socket.onerror = () => setStatus('erro na conexão');
socket.onmessage = (event) => {
const message = JSON.parse(event.data);
setMessages((current) => [...current, message]);
};
return () => socket.close();
}, []);
function sendMessage(event) {
event.preventDefault();
const socket = socketRef.current;
if (!draft.trim() || !socket || socket.readyState !== WebSocket.OPEN) return;
socket.send(draft.trim());
setDraft('');
}
return (
<main>
<h1>Chat de demonstração</h1>
<p>Conexão: {status}</p>
<form onSubmit={sendMessage}>
<input value={draft} onChange={(event) => setDraft(event.target.value)} maxLength={500} />
<button type='submit'>Enviar</button>
</form>
<ul>{messages.map((item, index) => <li key={index}>{item.text}</li>)}</ul>
</main>
);
}Como o servidor envia a mensagem de volta para todos os sockets que consegue enxergar, a própria mensagem aparece na lista. Para estudar primeiro, mantenha a tela simples; depois você pode estilizar o chat, mostrar o horário enviado e exibir mensagens diferentes enquanto a conexão está indisponível.
Passo 4: rode com o runtime local da Vercel
A API experimental de upgrade precisa do runtime da Vercel. Crie ou conecte sua conta e projeto com a CLI, depois inicie o ambiente local:
pnpm install
vercel link
vercel devAbra o endereço local informado no terminal. O uso de next dev não ativa o manipulador de upgrade da Vercel; para esse caminho de Next.js, teste com vercel dev. Abra duas abas e envie mensagens. Se as duas conexões forem atendidas pela mesma instância local, você verá a retransmissão. Depois teste uma aba em janela anônima para conferir um segundo cliente.
Se a conexão falhar, confirme que a rota é app/api/ws/route.js, que a dependência foi instalada e que o servidor foi iniciado com vercel dev. No navegador, abra as ferramentas de desenvolvedor e confira a aba Network, filtro WS. Um status de upgrade bem-sucedido indica que a conexão foi aberta; um 404 costuma apontar para o caminho ou arquivo incorreto.
Passo 5: publique um teste na Vercel
Envie o repositório para o GitHub e importe-o no painel da Vercel, ou use a CLI depois de conectar o projeto. Faça um deploy de preview antes de compartilhar o endereço. Teste com duas pessoas, dois navegadores e redes diferentes. Essa verificação ajuda a encontrar conexões que chegam a instâncias separadas.
WebSockets exigem Fluid Compute. Ele é habilitado por padrão em projetos mais recentes; projetos antigos podem precisar ativá-lo em Settings, Functions e fazer um novo deploy. A conexão também termina quando a Function alcança a duração máxima do plano, então um cliente real precisa reconectar e recuperar o estado perdido.
O que falta para transformar a demonstração em chat de produção?
O conjunto em memória não é compartilhado entre instâncias. Para que qualquer pessoa veja a mensagem de qualquer outra, adicione uma camada compartilhada de publicação e assinatura, como Redis. O Redis recebe o evento enviado por uma instância e o distribui às outras. A Vercel descreve esse padrão no tutorial oficial de chat, que também trata de salas, histórico, presença, reconexão e variáveis de ambiente.
Um chat público também precisa de autenticação, limites de envio, validação de tamanho e conteúdo, política contra abuso, proteção contra spam e observabilidade. Não coloque mensagens privadas em logs e não assuma que uma conexão aberta identifica uma pessoa. Para salas privadas, valide a autorização antes de aceitar ou retransmitir mensagens.
A Vercel cobra WebSockets segundo o modelo das Functions. O Active CPU é contado enquanto o código processa mensagens; a memória provisionada continua associada à instância enquanto houver trabalho em andamento. Uma conexão aberta não deve ser descrita como totalmente gratuita. Consulte os limites e o uso do seu plano antes de colocar tráfego real.
O próximo passo para um chat confiável é tirar o estado da memória local e compartilhá-lo com Redis, além de adicionar autenticação e reconexão.
