FastAPI is a modern Python web framework optimized for APIs, but when you need caching, rate limiting, or session storage, you need a key-value store. PandaStack provisions a managed Redis instance and injects connection variables into your app automatically, so you can start caching responses without provisioning infrastructure or managing connection strings.
This post shows how to deploy a FastAPI app with a linked KV store, how to connect with both the native Redis client and the HTTP REST API, and how to handle connection pooling under load.
What is the KV store
PandaStack's KV store is a managed Redis instance, provisioned independently of the SQL databases (PostgreSQL and MySQL). When you link it to a container app, three environment variables are injected:
KV_URL: Redis connection string (redis://default:password@host:6379)KV_REST_API_URL: HTTP endpoint for REST-based accessKV_REST_API_TOKEN: Bearer token for the REST API
You can connect with any Redis client using KV_URL, or use the REST API for serverless/edge environments where persistent TCP connections aren't available.
A minimal FastAPI app
Start with a basic FastAPI app:
# app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello from FastAPI"}Install dependencies:
pip install fastapi uvicorn[standard]Run it locally:
uvicorn app:app --host 0.0.0.0 --port 8000Critical: bind to 0.0.0.0, not 127.0.0.1. Container deployments route traffic via the pod IP, and binding to localhost makes the app unreachable. This is the most common reason FastAPI apps deploy successfully but don't respond to requests.
Adding Redis for caching
Install the redis client:
pip install redisCreate a Redis client that reads KV_URL:
# app.py
import os
import redis
from fastapi import FastAPI
app = FastAPI()
# Connect to Redis using KV_URL
kv_url = os.getenv("KV_URL")
if kv_url:
redis_client = redis.from_url(kv_url, decode_responses=True)
else:
redis_client = None
@app.get("/")
def read_root():
return {"message": "Hello from FastAPI"}
@app.get("/cached")
def cached_route():
if not redis_client:
return {"error": "KV store not configured"}
cached = redis_client.get("cached_value")
if cached:
return {"value": cached, "source": "cache"}
# Simulate expensive computation
value = "computed_value"
redis_client.setex("cached_value", 60, value) # Cache for 60 seconds
return {"value": value, "source": "computed"}This route checks Redis for cached_value. If it exists, the cached value is returned. Otherwise, the value is computed and stored in Redis with a 60-second TTL.
Deploying the app
Create a requirements.txt:
fastapi
uvicorn[standard]
redisAdd a pandastack.json to specify the start command:
{
"type": "container",
"language": "python",
"startCommand": "uvicorn app:app --host 0.0.0.0 --port $PORT",
"healthCheckPath": "/"
}The $PORT variable is injected by PandaStack (defaults to 8000). Uvicorn reads it from the environment.
Push the repo to GitHub, then deploy via the API:
curl -X POST https://api.pandastack.io/v1/projects \
-H "Authorization: Bearer psk_live_your_token" \
-H "Content-Type: application/json" \
-d '{
"slug": "container",
"name": "fastapi-kv",
"repositoryName": "yourusername/fastapi-kv",
"branch": "main",
"autoDeploy": true
}'The response includes a projectId. Save it.
Provisioning the KV store
Create a Redis instance via the dashboard (Databases → KV Stores → Create) or the API:
curl -X POST https://api.pandastack.io/v1/kv-stores \
-H "Authorization: Bearer psk_live_your_token" \
-H "Content-Type: application/json" \
-d '{ "name": "fastapi-cache" }'The response includes the KV_URL and REST API credentials.
Linking the KV store to the app
Link the KV store in the dashboard: go to the project's Environment tab, click Link KV Store, and select the Redis instance. This injects KV_URL, KV_REST_API_URL, and KV_REST_API_TOKEN and redeploys the app.
Alternatively, set the environment variables manually:
curl -X POST https://api.pandastack.io/v1/projects/42/env \
-H "Authorization: Bearer psk_live_your_token" \
-H "Content-Type: application/json" \
-d '{
"env": [
{ "name": "KV_URL", "value": "redis://default:pass@host:6379" }
]
}'Then trigger a redeploy:
curl -X POST https://api.pandastack.io/v1/projects/42/deploy \
-H "Authorization: Bearer psk_live_your_token"The next deploy reads KV_URL at runtime and connects to the managed Redis instance.
Using the HTTP REST API
If you're deploying to an edge environment or want to avoid managing TCP connections, use the HTTP REST API instead of the native Redis client:
import os
import httpx
from fastapi import FastAPI
app = FastAPI()
kv_rest_url = os.getenv("KV_REST_API_URL")
kv_rest_token = os.getenv("KV_REST_API_TOKEN")
@app.get("/cached-rest")
async def cached_rest_route():
if not kv_rest_url or not kv_rest_token:
return {"error": "KV REST API not configured"}
headers = {"Authorization": f"Bearer {kv_rest_token}"}
# GET key
async with httpx.AsyncClient() as client:
resp = await client.get(f"{kv_rest_url}/get/cached_value", headers=headers)
if resp.status_code == 200 and resp.json().get("result"):
return {"value": resp.json()["result"], "source": "cache"}
# SET key with 60s TTL
value = "computed_value"
await client.post(
f"{kv_rest_url}/set/cached_value",
headers=headers,
json={"value": value, "ex": 60}
)
return {"value": value, "source": "computed"}Install httpx:
pip install httpxThe REST API is compatible with Upstash's protocol, so you can use Upstash client libraries if you prefer.
Connection pooling
The native redis-py client uses a connection pool by default. If you deploy multiple replicas of your app, each replica opens its own pool (default: up to 50 connections per pool). Redis can handle thousands of connections, but if you scale to many replicas, you may hit limits.
To limit connections per replica, configure the pool size:
redis_client = redis.from_url(
kv_url,
decode_responses=True,
max_connections=10
)With 5 replicas and 10 connections each, you use 50 total connections.
The HTTP REST API doesn't use persistent connections, so connection pooling isn't a concern. Each request is a short-lived HTTP call.
Testing the API
Once deployed, the dashboard shows the live URL (https://fastapi-kv-xyz.pandastack.app). Test the caching route:
curl https://fastapi-kv-xyz.pandastack.app/cached
# {"value":"computed_value","source":"computed"}
curl https://fastapi-kv-xyz.pandastack.app/cached
# {"value":"computed_value","source":"cache"}The first request computes the value and caches it. The second request returns the cached value. After 60 seconds, the cache expires, and the next request recomputes.
redis-cli caveat
The redis-cli tool does not send TLS SNI (Server Name Indication), so it cannot connect directly to PandaStack's managed Redis. Use a Redis client library instead, or use the dashboard's built-in Redis shell (Database → KV Store → Shell).
If you need redis-cli for debugging, connect via a TLS proxy like stunnel. The PandaStack docs have a guide for this.
Why this matters
Managed Redis is offered by AWS (ElastiCache), Azure (Cache for Redis), and Upstash. But ElastiCache requires VPC setup, Azure's offering is expensive for small workloads, and Upstash charges per request. PandaStack's KV store runs in the same Kubernetes cluster as your app, so latency is sub-5ms and there's no per-request charge.
The HTTP REST API makes it usable in serverless and edge environments where persistent TCP connections aren't available. This is the same pattern Upstash uses, and it's compatible with their client libraries.
Common use cases
Session storage: Store user sessions in Redis instead of a SQL database, reducing database load.
Rate limiting: Track API request counts per IP or user with INCR and EXPIRE.
Job queues: Use Redis lists or streams to queue background jobs (pair with Celery for Python).
Leaderboards: Use sorted sets (ZADD, ZRANGE) to maintain real-time leaderboards.
Cache invalidation: Store computed values with TTLs, invalidate manually with DEL.
Full project structure
fastapi-kv/
├── app.py # FastAPI app + Redis client
├── requirements.txt # Dependencies
├── pandastack.json # Deploy config
└── README.mdrequirements.txt:
fastapi
uvicorn[standard]
redis
httpxpandastack.json:
{
"type": "container",
"language": "python",
"startCommand": "uvicorn app:app --host 0.0.0.0 --port $PORT",
"healthCheckPath": "/",
"env": [
{
"key": "KV_URL",
"description": "Redis connection string (link a KV store in the dashboard)"
}
]
}Push this to GitHub, create the project, link the KV store, and the app is live with caching enabled.
References
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
- [redis-py Documentation](https://redis-py.readthedocs.io/)
- [Upstash REST API](https://upstash.com/docs/redis/features/restapi)
- [PandaStack KV Store Documentation](https://docs.pandastack.io/databases/kv-store)