How to Set Up Redis Caching for API Responses in FastAPI
FastAPI-Boilerplate provides a built-in Redis caching layer that automatically stores API responses and invalidates them on write operations using a simple decorator.
Setting up Redis caching for API responses in the benavlabs/fastapi-boilerplate repository requires configuring environment variables, initializing a connection pool on startup, and applying the @cache decorator to your endpoint functions. This architecture separates concerns between configuration management in src/app/core/config.py, lifecycle handling in src/app/core/setup.py, and the caching logic itself in src/app/core/utils/cache.py.
Configuring Redis Connection Settings
The boilerplate centralizes all Redis configuration in src/app/core/config.py. The Settings class constructs the connection URI from discrete environment variables, making it easy to switch between local development and production deployments.
Key environment variables recognized by the system:
REDIS_CACHE_HOST— defaults tolocalhost(userediswhen running via Docker Compose)REDIS_CACHE_PORT— defaults to6379REDIS_CACHE_DB— defaults to0REDIS_CACHE_PASSWORD— optional authentication string
The REDIS_CACHE_URL property dynamically assembles these into a standard Redis URI:
# src/app/core/config.py
f"redis://{self.REDIS_CACHE_HOST}:{self.REDIS_CACHE_PORT}"
Initializing the Redis Connection Pool
FastAPI-Boilerplate manages the Redis client lifecycle through startup and shutdown event handlers defined in src/app/core/setup.py. This ensures connections are pooled efficiently and released properly when the application terminates.
The create_redis_cache_pool function initializes the global cache object:
# src/app/core/setup.py
import redis
from .config import settings
from .utils import cache
async def create_redis_cache_pool() -> None:
cache.pool = redis.ConnectionPool.from_url(settings.REDIS_CACHE_URL)
cache.client = redis.Redis.from_pool(cache.pool)
Correspondingly, close_redis_cache_pool handles graceful teardown:
# src/app/core/setup.py
async def close_redis_cache_pool() -> None:
if cache.client is not None:
await cache.client.aclose()
These functions are registered as event handlers in src/app/main.py and execute automatically on application startup and shutdown.
Implementing the Cache Decorator
The @cache decorator in src/app/core/utils/cache.py provides the primary interface for Redis caching of API responses. It intercepts incoming requests, generates cache keys based on configurable parameters, and handles serialization automatically.
Basic Usage for GET Endpoints
Apply the decorator to any FastAPI endpoint function to cache its JSON response:
# src/app/api/v1/posts.py
from fastapi import APIRouter, Depends
from ...core.utils.cache import cache
from ...schemas.post import PostRead
router = APIRouter(prefix="/posts", tags=["posts"])
@router.get("/{id}", response_model=PostRead)
@cache(key_prefix="{username}_post_cache", resource_id_name="id")
async def read_post(id: int, current_user: User = Depends(get_current_user)):
# Database query executes only on cache miss
return await crud_posts.get(id)
The decorator constructs the Redis key by combining key_prefix with the value of the parameter specified in resource_id_name. For a user named alice requesting post 123, the key becomes alice_post_cache_123.
Cache Invalidation Strategies
For endpoints that modify data, configure the decorator to invalidate related cache entries automatically. The to_invalidate_extra parameter accepts a dictionary mapping key patterns to parameter names:
# src/app/api/v1/posts.py
@router.put("/{id}", response_model=PostRead)
@cache(
key_prefix="{username}_post_cache",
resource_id_name="id",
to_invalidate_extra={"{username}_posts": "{username}"}
)
async def update_post(id: int, post_update: PostUpdate):
# Updates the post and clears the user's post list cache
return await crud_posts.update(id, post_update)
Alternatively, use pattern_to_invalidate_extra to clear multiple keys matching a glob pattern when you need to invalidate entire namespaces.
Docker Compose Configuration
The repository includes pre-configured Docker Compose files that provision a Redis instance for local development. The scripts/local_with_uvicorn/docker-compose.yml defines the service:
# scripts/local_with_uvicorn/docker-compose.yml
services:
redis:
image: redis:alpine
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
volumes:
redis-data:
When running via docker compose up web db redis, the application connects to Redis using the service name redis as the host, matching the default configuration in .env.example.
Environment Setup Checklist
Configure your local environment before starting the application:
# .env
REDIS_CACHE_HOST=redis
REDIS_CACHE_PORT=6379
REDIS_CACHE_DB=0
# REDIS_CACHE_PASSWORD=optional-secret
Verify connectivity by checking application logs during startup for successful pool creation, or test a cached endpoint and observe Redis key creation using redis-cli monitor.
Summary
- Configuration: Set
REDIS_CACHE_HOST,REDIS_CACHE_PORT, andREDIS_CACHE_DBin your environment or.envfile, with the URL constructed automatically insrc/app/core/config.py. - Connection Management: The application initializes a
redis.ConnectionPoolon startup viacreate_redis_cache_pool()insrc/app/core/setup.pyand closes it gracefully on shutdown. - Decorator Usage: Apply
@cache(key_prefix="...", resource_id_name="...")fromsrc/app/core/utils/cache.pyto GET endpoints to enable automatic response caching. - Invalidation: Use
to_invalidate_extraorpattern_to_invalidate_extraparameters in the decorator to clear related cache entries when data changes. - Infrastructure: Docker Compose files in
scripts/local_with_uvicorn/provide a ready-to-use Redis service configured for the boilerplate's defaults.
Frequently Asked Questions
How do I change the Redis database number or add authentication?
Modify the environment variables in your .env file. Set REDIS_CACHE_DB to the desired integer (0-15 for standard Redis) and provide REDIS_CACHE_PASSWORD if your Redis instance requires authentication. The REDIS_CACHE_URL property in src/app/core/config.py automatically incorporates these values when constructing the connection string.
Can I use the cache decorator on non-GET endpoints?
Yes, though the behavior differs. The @cache decorator in src/app/core/utils/cache.py primarily targets GET requests for retrieval caching. When applied to POST, PUT, or DELETE endpoints, it functions as an invalidation mechanism—clearing specified cache keys after the operation completes—rather than storing the response. Use to_invalidate_extra to specify which keys to clear when mutating data.
What happens if the Redis server is unavailable?
The application handles Redis unavailability gracefully during startup and runtime. If the connection pool fails to initialize in create_redis_cache_pool(), the application will raise a connection error on startup, preventing deployment with misconfigured cache settings. At runtime, if Redis becomes unreachable, the @cache decorator falls back to executing the endpoint function directly, bypassing the cache layer without crashing the request—though this results in cache misses until connectivity is restored.
How do I monitor cache hit rates and inspect stored keys?
Connect to your Redis instance using redis-cli or a GUI client like RedisInsight. Run MONITOR to observe real-time key operations as the @cache decorator executes GET, SET, and EXPIRE commands. To list keys matching your prefix, use KEYS {username}_post_cache_* (replace with your actual prefix). For production monitoring, integrate Redis metrics into your observability stack using the INFO stats command to track hit/miss ratios and memory usage.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →