Redis is an in-memory data store commonly used for caching, rate limiting, session storage, and temporary data. In a FastAPI application, Redis can reduce repeated database queries and share data across multiple application workers.
The easiest way to run Redis locally is with Docker:
docker run -d \--name redis \-p 127.0.0.1:6379:6379 \redis:7-alpine
Verify that Redis is running:
docker exec -it redis redis-cli ping
Expected output:
PONG
Redis is now available on localhost:6379. Binding to 127.0.0.1 keeps the port accessible only from the local machine.
Install FastAPI, Uvicorn, and the Redis Python client:
pip install fastapi uvicorn redis
The redis package provides an asynchronous client through redis.asyncio, making it suitable for asynchronous FastAPI endpoints.
A simple project structure might look like this:
fastapi-app/├── app/│ ├── __init__.py│ ├── main.py│ └── redis.py└── requirements.txt
Create app/redis.py:
import osimport redis.asyncio as redisredis_client = redis.from_url(os.getenv("REDIS_URL", "redis://localhost:6379/0"),decode_responses=True,)
A Redis connection URL generally follows this format:
redis://[username]:[password]@[host]:[port]/[database]
localhost: Redis host during local development.6379: Default Redis port.0: Redis database index.decode_responses=True: Returns strings instead of bytes for text responses.For production, configure the URL through environment variables and use appropriate authentication and network access controls.
Use FastAPI’s lifespan handler to initialize and close the Redis client.
from contextlib import asynccontextmanagerfrom fastapi import FastAPI, Requestfrom app.redis import redis_client@asynccontextmanagerasync def lifespan(app: FastAPI):await redis_client.ping()app.state.redis = redis_clienttry:yieldfinally:await redis_client.aclose()app = FastAPI(lifespan=lifespan)@app.get("/health/redis")async def redis_health(request: Request):await request.app.state.redis.ping()return {"status": "Redis is connected"}
The lifespan handler runs before the application starts accepting requests and closes the client during shutdown.
The initial ping() verifies connectivity. If Redis is unavailable, application startup fails. This is appropriate when Redis is a required dependency; applications that can operate without caching may instead use a deliberate degraded-service strategy.
Each application worker should have its own Redis client and connection pool. If you run multiple workers, each worker initializes and closes its own client.
Redis supports simple key-value operations with an optional time-to-live (TTL).
Add these endpoints to app/main.py:
from fastapi import HTTPException, Request@app.put("/cache/{key}")async def set_cache(key: str,value: str,request: Request,):client = request.app.state.redisawait client.set(key, value, ex=300)return {"message": "Value stored successfully"}@app.get("/cache/{key}")async def get_cache(key: str, request: Request):client = request.app.state.redisvalue = await client.get(key)if value is None:raise HTTPException(status_code=404,detail="Cache key not found",)return {"key": key, "value": value}
The ex=300 option sets a TTL of 300 seconds, or five minutes. Redis automatically expires the key after that period.
For example, storing hello under the key greeting makes it available until the key expires or is deleted.
In production, validate keys and values, avoid exposing unrestricted cache access, and use an appropriate serialization format for structured data.
Start the development server:
uvicorn app.main:app --reload
Open the interactive API documentation at http://127.0.0.1:8000/docs.
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /health/redis | Check Redis connectivity |
| PUT | /cache/{key}?value=hello | Store a value |
| GET | /cache/{key} | Retrieve a value |
For example, call PUT /cache/greeting?value=hello, then call GET /cache/greeting to retrieve the stored value.
Redis becomes especially useful as your application grows.
When implementing a cache, define a clear expiration policy and consider invalidation whenever the underlying data changes. Redis is typically an optimization layer, not a replacement for your primary database.
redis.asyncio integrates with FastAPI’s async endpoints.Redis is a useful building block for improving performance and coordinating state in production FastAPI applications.