redis/fastapi-redis-sdk
> fastapi-redis-sdk development skill. Use when writing code, tests, or configuration for the fastapi-redis-sdk library — the official Redis integration for FastAPI. Covers project setup (uv + nox), DI-based caching patterns, connection lifecycle, async/sync endpoints, testing conventions, and CI workflows. Do NOT use for general Redis or FastAPI questions unrelated to this library.
npx skills add https://github.com/redis/fastapi-redis-sdk --skill fastapi-redis-sdk
Official Redis integration for FastAPI — connection management and DI-based
caching with automatic key consistency.
src/redis_fastapi/ # Library source (single flat package)
__init__.py # Public API re-exports
setup.py # FastAPIRedis fluent builder
lifespan.py # redis_lifespan async context manager
deps.py # FastAPI DI factories & type aliases
config.py # RedisSettings (pydantic-settings)
cache.py # cache(), cache_evict(), cache_put() + middleware
cache_backend.py # CacheBackend (async) + SyncCacheBackend
telemetry.py # Optional OpenTelemetry instrumentation
types.py # Coder, KeyBuilder protocols
tests/
unit/ # fakeredis-based, no real Redis needed
integration/ # Requires Redis on localhost:6379
pyproject.toml # uv build backend, dependency groups, tool config
noxfile.py # CI-mirroring sessions (lint, typecheck, security, tests, docs)
Package manager: uv. Task runner: nox (with uv venv backend).
uv sync --all-groups # Install all deps
uv run nox # Run ALL CI checks locally
uv run nox -s lint # Lint + format check only
uv run nox -s typecheck # mypy
uv run nox -s tests-3.12 # Full suite on a specific Python version
uv run nox -s tests_unit-3.12 # Unit suite only (fakeredis, no server)
uv run nox -s tests_integration-3.12 # Integration suite only (needs Redis)
uv run nox -s fix # Auto-fix lint/format
uv run nox -s docs_serve # Live-reload docs at localhost:8000
Redis pools MUST be initialised via the app lifespan. There is no fallback.
Accessing the pool without a lifespan raises RuntimeError.
app = FastAPI()
FastAPIRedis(app).lifespan().caching() # Always call .lifespan()
get_async_redis, get_cache_backend) are async.SyncCacheBackend wraps async calls via anyio.from_thread.run —use only from sync endpoints running in FastAPI's worker threads.
from redis_fastapi import AsyncRedisDep, CacheBackendDep, SyncCacheBackendDep
# Async endpoint — use AsyncRedisDep or CacheBackendDep
async def endpoint(redis: AsyncRedisDep): ...
async def endpoint(cache: CacheBackendDep): ...
# Sync endpoint — use SyncCacheBackendDep
def endpoint(cache: SyncCacheBackendDep): ...
.lifespan() wraps the app's existing lifespan — it does not replace it.
Multiple builder calls nest around whatever is already there. For explicit
ordering, skip .lifespan() and compose manually with redis_lifespan:
from redis_fastapi import FastAPIRedis, redis_lifespan
@asynccontextmanager
async def my_lifespan(app):
async with redis_lifespan(app):
async with db_lifespan(app):
yield
app = FastAPI(lifespan=my_lifespan)
FastAPIRedis(app).caching() # no .lifespan() — user owns it
See docs/guide/architecture.md § Lifespan wrapping for details.
Two patterns, same pool:
cache(ttl=N, eviction_group="x"), cache_evict(...),cache_put(...) as Depends(). Requires .caching() on setup.
get/set/delete/has/delete_group.For conditional logic, cascade invalidation, dynamic TTL.
timedelta for TTL (DI factories accept int seconds only).Choose cache() for most GET endpoints. Choose CacheBackend when you
need conditional caching, multi-step invalidation, or custom serializers.
cache_evict()/cache_put() bridge writes back to the same cache keys.
CacheHitException → exception handlerreturns cached response. Endpoint never executes.
CacheResponseCaptureMiddleware buffers the response bodyand stores it in Redis after the endpoint returns.
See docs/guide/architecture.md § Why not a full ASGI middleware.
Cached entries are Redis string keys with eviction-group prefixes.
Namespace deletion uses SCAN + DEL. Hash-based storage (faster
eviction-group deletion via single DEL) is a future opt-in gated on
Redis ≥ 8.0. See docs/guide/architecture.md § Storage model.
Three independent OTel layers (each opt-in):
opentelemetry-instrumentation-fastapi (external).FastAPIRedis(app)...otel() orREDIS_OTEL_ENABLED=true. Install fastapi-redis-sdk[otel].
REDIS_OTEL_REDIS_ENABLED=true oropentelemetry-instrumentation-redis (not both).
See docs/guide/architecture.md § Telemetry for span names and metrics.
tests/unit/): use fakeredis.aioredis, no real Redis.tests/integration/): real Redis, decorated with@requires_redis (auto-skip if server unreachable).
filterwarnings = ["error"] in pytest config — all warnings are errors.--cov-fail-under=80). The integration-onlysession lowers this to 70 (_INTEGRATION_COV_FLOOR in noxfile.py) —
83 integration tests alone cover ~78% of src/.
unit-tests runstests_unit across 3 OSes x 5 Pythons, integration-tests runs
tests_integration against Redis 8.8 and 7.4. See
docs/guide/compatibility.md § 4.
asyncio_mode = "auto" — no need for @pytest.mark.asyncio.fake_async_redis — fakeredis instance, available in unit tests.real_redis / real_async_redis — real Redis clients for integration.All settings via env vars prefixed REDIS_ or .env file.
Key vars: REDIS_URL, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD,
REDIS_SSL, REDIS_CLUSTER, REDIS_PREFIX, REDIS_DEFAULT_TTL.
from __future__ import annotations in all source files.Union[] (not X | Y) for Python 3.10 compat indeps.py and types.py (ruff rule UP007 ignored there).
CI is defined in .github/workflows/ci.yml and delegates to nox sessions.
Do NOT add inline uv run ruff / uv run mypy commands to CI — use
uv run nox -s <session> so CI and local checks stay in sync.
uv_build as its build backend.NEVER replace it with hatchling, setuptools, flit, or any other
build backend. All build config lives in pyproject.toml under
[build-system] and [tool.uv.build-backend].
Depends() factories(cache(), cache_evict(), cache_put()), NOT as decorators. NEVER
refactor DI based solutions to use a decorator-based approach (@cache). The DI
pattern is a deliberate design decision, see /guide/architecture.md
for more information.
Default key: {prefix}:{eviction_group}:{path}:{sorted_query_params}.
Eviction group is wrapped in hash-tag braces {ns} for Redis Cluster
slot alignment. Query params are sorted alphabetically for determinism.
Headers are NOT part of the key — use a custom key_builder for
header-dependent responses (e.g. Accept).
Fixed-window expiry. Accessing a cached entry does NOT extend its TTL.
ttl=0 or ttl=None means no automatic expiration.
All Redis errors (RedisError, OSError) are caught and logged as
warnings. Cache reads return None/miss; writes are silently dropped.
Exceptions from endpoints are never cached — only successful responses.
Corrupted cache data is treated as a miss (auto-fallback).
anyio.from_thread.run takes a zero-arg callable returning anawaitable, NOT a coroutine object. Wrap with lambda.
SyncCacheBackendDep must be imported at module level when usingfrom __future__ import annotations, or FastAPI cannot resolve the type.
uv add --dev in CI workflows — deps are managed by noxsessions and pyproject.toml dependency groups.
cache() reads get_settings() at dependency-creation time (when themodule loads), not per-request. Runtime setting changes won't be picked
up by already-registered routes.
Take redis/fastapi-redis-sdk from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.