web

Fastapi Websockets: Build Real-time Apps Fast

Building real time web applications requires a communication layer that bypasses traditional HTTP request response cycles. When you're building live dashboards, collaborative tools, or streaming feeds

Fastapi Websockets: Build Real-time Apps Fast
In this story

Building real-time web applications requires a communication layer that bypasses traditional HTTP request-response cycles. When you're building live dashboards, collaborative tools, or streaming feeds, you need persistent, low-latency channels. FastAPI handles this natively using WebSockets, giving you async Python performance without complex setup.

This guide walks through building a production-ready, full-stack real-time application using FastAPI, asynchronous handlers, and a modern frontend client. You'll learn how to manage connection states, broadcast messages efficiently, and structure your project for scalability.

Setting Up the FastAPI Backend

To start, you need an isolated environment and the core dependencies. FastAPI relies on Uvicorn as an ASGI server to handle concurrent asynchronous connections.

Installing Dependencies

Open your terminal and run these commands to set up your project folder and virtual environment:

mkdir fastapi-realtime
cd fastapi-realtime
python -m venv venv
source venv/bin/activate
pip install fastapi uvicorn websockets

Creating the Core Application

Create a main.py file. We'll set up a connection manager class to track active client connections and broadcast data streams safely across threads.

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from typing import List

app = FastAPI()

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):
        self.active_connections.remove(websocket)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)

manager = ConnectionManager()

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.broadcast(f"Client {client_id}: {data}")
    except WebSocketDisconnect:
        manager.disconnect(websocket)
        await manager.broadcast(f"Client {client_id} left the chat")

Building the Frontend Client

Real-time applications need a client capable of maintaining an open socket. We can use native browser JavaScript to interface with our FastAPI backend. Create an index.html file in your root directory:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    Real-Time Dashboard
</head>
<body>
    <h1>Live Stream Client</h1>
    <form id="form">
        <input type="text" id="messageText" autocomplete="off" placeholder="Type a message..." />
        <button>Send</button>
    </form>
    <ul id="messages"></ul>

    <script>
        const clientId = Date.now();
        const ws = new WebSocket(`ws://localhost:8000/ws/${clientId}`);

        ws.onmessage = function(event) {
            const messages = document.getElementById('messages');
            const message = document.createElement('li');
            message.textContent = event.data;
            messages.appendChild(message);
        };

        document.getElementById('form').onsubmit = function(event) {
            event.preventDefault();
            const input = document.getElementById('messageText');
            ws.send(input.value);
            input.value = '';
        };
    </script>
</body>
</html>

To serve this file, add a simple static file router or mount it using FastAPI's static files module.

Managing State and Scaling Connections

As your application grows, handling thousands of concurrent WebSocket connections inside a single server instance becomes a bottleneck. In-memory lists like active_connections fail when you scale horizontally across multiple server containers.

To fix this, implement a message broker like Redis. When a client sends a message, your FastAPI instance publishes it to a Redis channel. Every backend worker subscribes to that channel, ensuring messages sync across all connected clients regardless of which server instance they hit.

Common Implementation Pitfalls

  • Ignoring Ping-Pawn Frames: Idle TCP connections often drop due to proxy timeouts. Implement periodic ping-heartbeats to keep sockets alive.
  • Blocking the Event Loop: Running synchronous database queries inside async websocket routes freezes the server. Use async database drivers like asyncpg or SQLModel with async sessions.
  • Unbounded Queues: If a client slows down, unread messages pile up in memory. Set strict queue limits or drop stale data frames.

Frequently Asked Questions

How do I authenticate WebSocket connections in FastAPI?

Standard HTTP headers can be passed during the initial WebSocket handshake. You can extract query parameters or cookies inside the @app.websocket endpoint to validate tokens before accepting the connection.

Can FastAPI handle WebSockets and standard REST endpoints simultaneously?

Yes. FastAPI runs on Starlette, which handles standard HTTP routing and WebSocket routing within the same application instance without performance penalties.

What is the best way to handle reconnection logic on the frontend?

Implement exponential backoff in your JavaScript client. If the socket closes unexpectedly, wait two seconds, then four, then eight, trying to reconnect until the server responds.

Why is my WebSocket connection dropping after 60 seconds?

Load balancers like Nginx or AWS ALB terminate idle connections by default. Adjust your proxy timeout configurations and enable periodic heartbeat pings in your application code.

CR

Written by

Chloe Ramirez

Chloe Ramirez excels at making complicated information accessible, turning dense research into clear narratives that engage diverse audiences.

More from web