---
name: redis-fastapi
description: "Provisions a Redis database (Upstash-compatible, REST and TCP) for a FastAPI app with `npx extraorbital add redis` (no signup, no card) and wires it into FastAPI with `redis`. Use when a FastAPI project needs Redis, a cache, rate limiting, sessions, a job queue, Upstash, Valkey or REDIS_URL, or when REDIS_URL is missing or unset in .env."
---

# Redis in FastAPI

<!-- Generated from ExtraOrbital's service registry by `pnpm skills:build` in platform/app. Edit the generator, not this file. -->

ExtraOrbital provisions a Redis database (Upstash-compatible, REST and TCP) in one command and writes the credentials into the project's env file. For anything this recipe does not cover, use the `extraorbital` skill or https://extraorbital.dev/llms.txt.

## 1. Provision

```bash
npx extraorbital add redis
```

Run it from the project root. It is idempotent (a second run returns the same resource) and writes to `.env.local` if the project has one, otherwise `.env`, keeping that file out of git. Add `--json` to parse the result; credential values are redacted there, and you should never print them either.

| Variable | |
| --- | --- |
| `UPSTASH_REDIS_REST_URL` | REST endpoint, for serverless and edge runtimes |
| `UPSTASH_REDIS_REST_TOKEN` | Its token |
| `REDIS_URL` | `rediss://` URL for any Redis-protocol client |

Free on the Prototype plan: 256 MB, 500K commands/mo.

## 2. Install the client

```bash
pip install pydantic-settings redis
```

## 3. Connect

`pydantic-settings` reads `.env` and `.env.local` itself; if `app/config.py` already exists, add the fields to its `Settings`.

**`app/config.py`**

```python
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    # ExtraOrbital writes .env.local when the project has one, else .env; the later file wins.
    model_config = SettingsConfigDict(env_file=(".env", ".env.local"), extra="ignore")

    REDIS_URL: str


settings = Settings()
```

**`app/redis_client.py`**

```python
from redis.asyncio import Redis

from app.config import settings

# rediss:// — TLS is in the URL.
redis = Redis.from_url(settings.REDIS_URL, decode_responses=True)
```

## 4. Use it

**`app/api/redis.py`**

```python
from fastapi import APIRouter

from app.redis_client import redis

router = APIRouter()
# In app/main.py: from app.api import redis; app.include_router(redis.router)


@router.get("/api/redis")
async def check_redis():
    hits = await redis.incr("hits")
    return {"hits": hits}
```

## 5. Verify

```bash
npx extraorbital list        # the resource is listed as active
fastapi dev app/main.py
curl http://localhost:8000/api/redis
```

A JSON answer means the credentials, the client and the route all work. Delete the route afterwards if the app does not need it.

## Pitfalls

- Both ways in reach the same database: the `UPSTASH_REDIS_REST_*` pair works with the `upstash-redis` package where a TCP connection is not an option.
- Set an expiry on cache keys (`ex`/`EX`): the Prototype allowance is 256 MB and 500K commands a month, across the account.
- A blocking client (`boto3`, `stripe`) belongs in a plain `def` route, which FastAPI runs in a threadpool; in `async def` it stalls every other request.
- With `uv`, `uv add` the same packages instead of `pip install`.
- Exit code 3 means the account is past its free allowance: show the human the link the command printed and wait. Do not retry or work around it.

Docs: https://extraorbital.dev/docs/resources/redis.md
