Home
Python
Redis with FastAPI: Caching and Async Integration
Daniel Nguyen
Daniel Nguyen
September 23, 2026
2 min

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.

1. Run Redis with Docker

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.

2. Install Dependencies

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.

3. Configure the Redis Connection

A simple project structure might look like this:

fastapi-app/
├── app/
│ ├── __init__.py
│ ├── main.py
│ └── redis.py
└── requirements.txt

Create app/redis.py:

import os
import redis.asyncio as redis
redis_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.

4. Manage the Connection Lifecycle

Use FastAPI’s lifespan handler to initialize and close the Redis client.

from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from app.redis import redis_client
@asynccontextmanager
async def lifespan(app: FastAPI):
await redis_client.ping()
app.state.redis = redis_client
try:
yield
finally:
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.

5. Store and Retrieve Values

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.redis
await 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.redis
value = 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.

6. Run and Test the Application

Start the development server:

uvicorn app.main:app --reload

Open the interactive API documentation at http://127.0.0.1:8000/docs.

MethodEndpointPurpose
GET/health/redisCheck Redis connectivity
PUT/cache/{key}?value=helloStore 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.

7. Common Production Use Cases

Redis becomes especially useful as your application grows.

  • Caching: Store frequently requested database results to reduce query load.
  • Rate limiting: Share request counters across multiple application workers.
  • Session storage: Store session data with expiration.
  • Pub/Sub: Distribute events between application processes.
  • Background jobs: Support queues and task-processing systems when paired with suitable libraries.

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.

Key Takeaways

  • Redis provides fast in-memory data access.
  • redis.asyncio integrates with FastAPI’s async endpoints.
  • FastAPI lifespan manages the Redis client’s lifecycle.
  • TTLs automatically expire temporary values.
  • Shared Redis storage helps coordinate data across multiple workers.

Redis is a useful building block for improving performance and coordinating state in production FastAPI applications.


Tags

#Python#FastAPI#Redis

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