Caching strategies in FastAPI

Difficulty: Intermediate

Question

What are different caching strategies you can use in a FastAPI application?

Answer

1. In-memory caching - Use `@lru_cache` or `cachetools` for simple function-level caching. Fast, but per-process and lost on restart.

2. Redis caching - Store responses or computed values in Redis with TTL. Shared across instances, persistent, and supports complex invalidation.

3. HTTP caching - Set `Cache-Control`, `ETag`, and `Last-Modified` headers. The client or CDN caches the response, reducing server load entirely.

4. fastapi-cache2 - A library that adds `@cache()` decorator support with Redis, Memcached, or in-memory backends. Automatic key generation from function arguments.

Cache invalidation is the hard part. Common strategies: - Time-based (TTL) - simplest - Event-based - invalidate on write operations - Cache-aside - check cache first, query DB on miss, store result

Code examples

Redis caching with fastapi-cache2

from fastapi import FastAPI
from fastapi_cache import FastAPICache
from fastapi_cache.backends.redis import RedisBackend
from fastapi_cache.decorator import cache
from redis import asyncio as aioredis
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    redis = aioredis.from_url("redis://localhost")
    FastAPICache.init(RedisBackend(redis), prefix="api-cache")
    yield

app = FastAPI(lifespan=lifespan)

@app.get("/products")
@cache(expire=300)  # Cache for 5 minutes
async def get_products():
    # Expensive DB query
    return await fetch_all_products()

@app.post("/products")
async def create_product(product: dict):
    await save_product(product)
    await FastAPICache.clear(namespace="api-cache")  # invalidate
    return product

Key points

Concepts covered

caching, Redis, in-memory cache, ETags, cache invalidation