Build a Real-Time Leaderboard with Redis and FastAPI
Imagine watching your game’s final match unfold, and seconds after a player crosses the finish line, their name instantly rockets to the top of the global leaderboard—no delays, no polling, no lag. That’s the power of a real-time leaderboard, and with Redis and FastAPI, you can build one in under an hour.
Leaderboards aren’t just for games. They fuel engagement in fitness apps, trading platforms, hackathons, and even customer support dashboards. But building one that updates instantly for thousands of users? That’s where most teams stumble. The secret lies in Redis’s sorted sets—a data structure designed specifically for ranking members by score with sub-millisecond performance.
Let’s cut through the noise and build a production-ready real-time leaderboard today.
Why Redis and FastAPI?
Redis is the gold standard for high-performance, real-time data. Its sorted set type (ZADD, ZREVRANGE, ZINCRBY) lets you add, update, and query ranked members in microseconds. Meanwhile, FastAPI is the fastest Python web framework, built on Starlette and Pydantic, with native async support and automatic OpenAPI docs.
Together, they give you:
- Instant score updates via Redis commands
-
Low-latency ranking queries with
ZREVRANGE - Real-time client updates using Redis Pub/Sub + Server-Sent Events (SSE)
- Zero WebSocket overhead—SSE works over plain HTTP
According to Redis’s official guide, sorted sets are the ideal foundation for gaming leaderboards, supporting time-based rankings, filtered views (e.g., by country), and atomic operations via Lua scripts [5].
Step 1: Set Up Your Redis Instance
You can run Redis locally or use Redis Cloud. For this tutorial, we’ll use a local instance.
On macOS:
brew install redis
redis-server
On Linux:
sudo apt install redis-server
redis-server
Verify it’s running:
redis-cli ping
# Should return: PONG
If you prefer cloud, Redis Cloud offers a free tier with instant setup and Redis Insight for visual debugging [1].
Step 2: Build the FastAPI Backend
Create a new directory and install dependencies:
mkdir redis-fastapi-leaderboard
cd redis-fastapi-leaderboard
pip install fastapi uvicorn redis python-sse
Now, create main.py:
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
import redis
import json
import asyncio
app = FastAPI()
redis_client = redis.Redis(host="localhost", port=6379, decode_responses=True)
LEADERBOARD_KEY = "game_leaderboard"
@app.post("/score")
async def add_score(member: str, score: int):
"""Increment or set a player's score"""
redis_client.zincrby(LEADERBOARD_KEY, score, member)
# Publish update for real-time clients
redis_client.publish("leaderboard_updates", json.dumps({"member": member, "score": score}))
return {"status": "updated", "member": member, "score": score}
@app.get("/leaderboard")
async def get_leaderboard(count: int = 10):
"""Get top N players"""
if count <= 0:
raise HTTPException(status_code=400, detail="count must be positive")
top_players = redis_client.zrevrange(LEADERBOARD_KEY, 0, count - 1, withscores=True)
return [{"member": p[0], "score": int(p[1])} for p in top_players]
@app.get("/stream")
async def stream_leaderboard():
"""Stream real-time leaderboard updates via SSE"""
async def generate():
pubsub = redis_client.pubsub()
pubsub.subscribe("leaderboard_updates")
while True:
message = pubsub.get_message(ignore_subscribe_messages=True)
if message:
data = json.loads(message["data"])
yield f"data: {json.dumps(data)}\n\n"
await asyncio.sleep(0.1)
return StreamingResponse(generate(), media_type="text/event-stream")
Run the server:
uvicorn main:app --reload
Your API is now live at http://localhost:8000. Test it with curl:
# Add scores
curl -X POST "http://localhost:8000/score?member=alice&score=150"
curl -X POST "http://localhost:8000/score?member=bob&score=200"
# Get leaderboard
curl "http://localhost:8000/leaderboard?count=5"
Expected output:
[{"member": "bob", "score": 200}, {"member": "alice", "score": 150}]
Step 3: Connect Real-Time Updates with Server-Sent Events
No need for WebSockets. SSE is simpler, works over HTTP, and scales effortlessly.
Create a simple HTML client in client.html:
<!DOCTYPE html>
<html>
<head><title>Real-Time Leaderboard</title></head>
<body>
<h1>🏆 Live Leaderboard</h1>
<ul id="leaderboard"></ul>
<script>
const list = document.getElementById("leaderboard");
const eventSource = new EventSource("/stream");
eventSource.addEventListener("message", (e) => {
const data = JSON.parse(e.data);
fetch(`/leaderboard?count=5`)
.then(res => res.json())
.then(players => {
list.innerHTML = "";
players.forEach((p, i) => {
const item = document.createElement("li");
item.textContent = `${i + 1}. ${p.member}: ${p.score}`;
list.appendChild(item);
});
});
});
</script>
</body>
</html>
Open client.html in your browser. Now, every time you call /score, the leaderboard refreshes instantly without polling.
Step 4: Scale for Millions (Optional but Critical)
For high-scale apps:
- Use Redis Pipelining to batch
ZADDoperations [5] - Enable TTL on leaderboard keys for daily/weekly resets [5]
- Use Lua scripts for atomic rank+score updates [5]
- Deploy Redis in cluster mode with sharding for horizontal scaling
CodeSignal’s guide confirms that ZINCRBY is essential for cumulative score leaderboards, while ZADD with GT/LT flags handles high/low-score tracking [5].
What You Can Do Today
You now have a fully functional real-time leaderboard that:
✅ Updates scores in milliseconds
✅ Returns top N players instantly
✅ Streams changes to clients via SSE
✅ Runs on local or cloud Redis
Try it in your next project:
- Add a
/scoreendpoint to your game backend - Replace your polling frontend with SSE
- Add a
?country=USfilter using Redis sorted set prefixes [5]
Ready to Go Further?
This isn’t just a tutorial—it’s a production pattern used by companies scaling to millions of users. The same architecture powers live trading dashboards [3], gaming tournaments [1], and hackathon ranking systems.
Your next step: Fork this code, add user authentication, and deploy it to your cloud provider. Then, share your leaderboard URL in the Dev.to comments—I’ll be the first to try it.
Let’s build real-time experiences that users actually feel. 🚀
If you found this helpful, consider buying me a coffee ☕ — it keeps these articles coming!
Also check out my AI tools collection: AI 次元世界 — free AI tools for developers.
💡 Related: **Content Creator Ultimate Bundle (Save 33%)* — $29.99*
🔒 Want More?
This article covers the basics. In Complete Python Automation Toolbox Bundle (Save 32%) ($24.99), you get:
- Complete source code
- Advanced techniques
- Real-world examples
- Step-by-step tutorials
- Bonus templates
Top comments (0)