Home
Python
WebSockets in FastAPI: Building Real-Time Applications
Daniel Nguyen
Daniel Nguyen
September 22, 2026
3 min

Modern applications often need real-time communication for chat, notifications, live dashboards, delivery tracking, and collaborative tools.

Traditional HTTP follows a request-response model:

Client → Request → Server
Client ← Response ← Server

The client typically needs to send another request to retrieve new data. WebSockets provide a persistent, bidirectional connection that allows the client and server to send messages at any time.

Client ←══════════→ Server
WebSocket

This makes WebSockets useful when applications need frequent updates with low latency.

1. Creating a WebSocket in FastAPI

FastAPI supports WebSocket endpoints through the @app.websocket() decorator.

from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
while True:
message = await websocket.receive_text()
await websocket.send_text(
f"Server received: {message}"
)
except WebSocketDisconnect:
pass

Import WebSocketDisconnect from fastapi to handle client disconnections.

The main operations are:

  • accept(): Accept the WebSocket connection.
  • receive_text(): Receive a text message.
  • send_text(): Send a text message.
  • close(): Close the connection.

The loop allows the client and server to continue communicating without establishing a new connection for every message.

2. Sending JSON Messages

Real applications usually exchange structured data rather than plain text.

data = await websocket.receive_json()
await websocket.send_json({
"username": data["username"],
"message": data["message"],
})

A client might send:

{
"username": "Viet",
"message": "Hello everyone!"
}

JSON provides a predictable structure for chat messages, notifications, and dashboard updates.

In production, validate incoming messages and avoid trusting client-provided fields such as usernames or roles. Derive identity from authenticated connection context instead.

3. Building a Real-Time Chat

A chat application needs to manage multiple active connections and distribute messages between them.

User A ─┐
User B ─┼──→ FastAPI → ConnectionManager
User C ─┘

A connection manager can track active WebSocket connections and broadcast messages.

from fastapi import WebSocket
class ConnectionManager:
def __init__(self):
self.active_connections: list[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
if websocket in self.active_connections:
self.active_connections.remove(websocket)
async def broadcast(self, message: str):
for connection in self.active_connections.copy():
await connection.send_text(message)

Create a manager and use it in an endpoint:

from fastapi import WebSocket, WebSocketDisconnect
manager = ConnectionManager()
@app.websocket("/ws")
async def chat_endpoint(websocket: WebSocket):
await manager.connect(websocket)
try:
while True:
message = await websocket.receive_text()
await manager.broadcast(message)
except WebSocketDisconnect:
manager.disconnect(websocket)

When a user sends a message, the server broadcasts it to all connected users, including the sender.

This is a minimal example. A production manager should also handle send failures, remove broken connections, authenticate users, and authorize access to individual chat rooms.

Important limitation: This connection list exists only in the current Python process. It does not automatically share connections across multiple workers or servers. For distributed applications, use a messaging layer such as Redis Pub/Sub to distribute events between processes.

4. Connecting WebSockets to React

React can connect to a WebSocket using the browser’s built-in WebSocket API.

const socket = new WebSocket("ws://localhost:8000/ws");
socket.onmessage = (event) => {
console.log(event.data);
};
socket.onopen = () => {
socket.send("Hello from React!");
};

For a React application, encapsulate connection management in a custom hook rather than creating connections during every render.

A typical lifecycle looks like this:

useEffect
↓
Create WebSocket
↓
Register event handlers
↓
Update React state
↓
Cleanup effect
↓
Close WebSocket

For example:

import { useEffect, useState } from "react";
export function useWebSocket(url: string) {
const [messages, setMessages] = useState<string[]>([]);
useEffect(() => {
const socket = new WebSocket(url);
socket.onmessage = (event) => {
setMessages((previous) => [...previous, event.data]);
};
return () => {
socket.close();
};
}, [url]);
return messages;
}

The cleanup function closes the connection when the component unmounts or the URL changes. Production hooks should also handle connection status, errors, reconnection, and message parsing.

Use wss:// instead of ws:// when connecting securely in production over HTTPS.

5. Building a Live Data Dashboard

WebSockets are useful for dashboards that need continuous updates, such as sensor readings, delivery locations, or application metrics.

A typical architecture looks like this:

Background Task
↓
Generate or Retrieve Data
↓
Publish Event
↓
WebSocket Connection
↓
React Dashboard

For example, a server can periodically publish sensor readings as JSON, and React can update the displayed values as messages arrive.

With HTTP polling, the client repeatedly requests updates:

GET /sensor
GET /sensor
GET /sensor
GET /sensor

With WebSockets, the server can push new values as they become available:

Server ── data ──→ React
Server ── data ──→ React
Server ── data ──→ React

WebSockets reduce repeated request overhead when updates are frequent. However, for infrequent updates or simpler applications, ordinary HTTP polling or Server-Sent Events (SSE) may be easier to maintain.

6. Handling Disconnects and Reconnection

Network failures and disconnected clients are normal in real-time applications. The server must remove disconnected clients, while the frontend should recover when connections are interrupted.

FastAPI raises WebSocketDisconnect when a connection closes during normal receive operations.

from fastapi import WebSocketDisconnect
try:
while True:
message = await websocket.receive_text()
await manager.broadcast(message)
except WebSocketDisconnect:
manager.disconnect(websocket)

Production applications should also consider:

  • Graceful disconnects: Remove closed connections from the manager.
  • Heartbeats: Detect connections that are no longer responsive.
  • Reconnection: Restore connectivity after temporary failures.
  • Exponential backoff: Increase the delay between failed reconnection attempts.
  • Error handling: Remove connections that fail during message delivery.

A reconnection strategy might use the following delays:

1s → 2s → 4s → 8s → 16s → 30s

Add a maximum delay and random jitter to prevent many clients from reconnecting simultaneously. If messages must not be lost, consider message IDs, acknowledgements, and a persistent event store; reconnecting alone does not guarantee delivery.

Key Takeaways

  • WebSockets enable persistent, bidirectional communication.
  • FastAPI provides WebSocket endpoints for receiving and sending messages.
  • Connection managers track clients and broadcast messages.
  • React hooks help manage connection lifecycles and incoming messages.
  • Redis Pub/Sub can distribute events across multiple server processes.
  • Reconnection and error handling improve reliability in production.

WebSockets are a strong choice for applications that need frequent, low-latency updates. A production implementation should combine connection management with authentication, authorization, resource limits, and a clear strategy for handling failures.


Tags

#Python#FastAPI

Share

Daniel Nguyen

Daniel Nguyen

Frontend Developer

Frontend developer specializing in React, Next.js, and JavaScript. Writing practical guides on modern web development at Dev98.

Expertise

React
Next.js
JavaScript
TypeScript
Python

Social Media

githublinkedinyoutubewebsite

Related Posts

AI
Building an AI Gateway with FastAPI
October 06, 2026
2 min
Dev98

Dev98

React · Next.js · Web development