Python

WebSocket Servers in Python with FastAPI or Starlette

Introduction

Real-time features such as live notifications, chat messaging, dashboards, and collaborative tools all rely on persistent, low-latency communication between client and server. Python developers frequently choose FastAPI or Starlette when implementing WebSocket servers, as both frameworks provide a clean, asynchronous interface for handling two-way communication. In this guide, you will learn how WebSockets work in Python, how FastAPI and Starlette implement them, and what patterns you should follow to build scalable and reliable real-time systems.

Why WebSockets Matter

Many modern applications require immediate updates rather than periodic polling. WebSockets support this by maintaining a continuous connection between the client and the backend. As a result, systems gain important benefits.

• Real-time event updates across connected clients
• Lower latency compared to repeated HTTP calls
• Reduced server load due to persistent connections
• Better user experience for chat, games, analytics, and collaboration
• A more interactive and dynamic frontend

Python’s async ecosystem, especially FastAPI and Starlette, offers excellent foundations for these use cases.

How WebSockets Work

WebSockets allow the server and client to communicate over a single, persistent TCP connection. This differs from HTTP, which is stateless and represents each request independently. WebSocket communication includes three stages.

Handshake

The browser initiates a connection using a special HTTP Upgrade header, and the server switches to the WebSocket protocol.

Bidirectional Messaging

Once connected, both sides can send and receive messages at any time without waiting for a request cycle.

Connection Lifecycle

Clients may disconnect voluntarily, or the server may end the session. Heartbeats are often used to keep connections alive.

Understanding these patterns helps you design reliable real-time communication flows.

WebSocket Support in FastAPI

FastAPI includes first-class WebSocket support, building directly on top of Starlette while adding type hints, dependency injection, and clean async design.

Basic Example

from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        message = await websocket.receive_text()
        await websocket.send_text(f"Received: {message}")

Clients can now connect to /ws and send messages interactively.

Broadcasting Messages to Multiple Clients

connections = []

@app.websocket("/ws/chat")
async def chat_socket(websocket: WebSocket):
    await websocket.accept()
    connections.append(websocket)

    try:
        while True:
            data = await websocket.receive_text()
            for conn in connections:
                await conn.send_text(data)
    finally:
        connections.remove(websocket)

This pattern allows multiple clients to join a real-time channel. For production use, you should add error handling and heartbeat checks.

WebSocket Support in Starlette

Since FastAPI builds on Starlette, you can also use Starlette directly for lightweight WebSocket servers. The API is simple and minimal.

Basic Example

from starlette.applications import Starlette
from starlette.endpoints import WebSocketEndpoint
from starlette.routing import WebSocketRoute

class Echo(WebSocketEndpoint):
    async def on_connect(self, websocket):
        await websocket.accept()

    async def on_receive(self, websocket, data):
        await websocket.send_text(f"Echo: {data}")

app = Starlette(routes=[WebSocketRoute("/ws", Echo)])

Starlette is ideal for developers who prefer a micro-framework without additional abstractions.

Handling Errors, Disconnects, and Heartbeats

WebSocket applications must account for broken connections or idle sessions. Consider the following patterns.

• Use try/except blocks to catch disconnections
• Implement periodic heartbeat messages to keep clients active
• Validate messages before processing
• Close idle connections with timeouts
• Clean up resources to prevent memory leaks

Following these techniques ensures your WebSocket server remains reliable under load.

Scaling WebSocket Servers

Scaling WebSocket applications requires a different approach from traditional HTTP workloads because each connection stays open for a long time.

Using a Pub/Sub Layer

For distributed systems with multiple worker instances, use a shared backend such as Redis Pub/Sub to broadcast messages.

Running Behind ASGI Servers

ASGI servers like Uvicorn or Hypercorn support asynchronous events and are built for real-time workloads.

Load Balancing

Layer-4 or sticky-session load balancing helps maintain persistent client connections.

As your system grows, these techniques ensure smooth real-time communication across distributed nodes.

When to Choose FastAPI or Starlette

Both frameworks support WebSockets well, but they excel in different scenarios.

FastAPI is ideal when you need:
• Dependency injection
• Type hints for improved development experience
• A full web API and WebSockets in the same project
• Integrated validation using Pydantic

Starlette is a better choice when you want:
• A lightweight ASGI toolkit
• Maximum control with minimal abstractions
• Lower overhead for microservices or gateways

Understanding the strengths of each framework helps you pick the right tool for your system.

Conclusion

WebSocket support in FastAPI and Starlette enables Python developers to build fast, efficient, and fully interactive real-time applications. These frameworks offer clean async interfaces, strong performance, and excellent integration with modern ASGI servers. If you want to continue exploring Python backend design, read “How to Build a REST API in Python Using FastAPI.” For deeper insights into asynchronous patterns, see “Mastering Async/Await in JavaScript: A Beginner-Friendly Guide.” To explore official documentation, visit the FastAPI documentation and the Starlette documentation. Using these tools effectively helps you deliver scalable, real-time features that enhance the experience of your users.

Leave a Comment