Deploy FastAPI to Production: Zero-Config Guide
Deploy FastAPI to production with Temps: zero-config Python deploys, an auto-generated Dockerfile, automatic HTTPS and built-in error tracking, in one guide.
Temps Team · January 30, 2026 · 6mo ago
Deploying FastAPI to production without a dedicated DevOps team means juggling Docker, Nginx, SSL certificates, and monitoring tools that rarely work together cleanly. Temps collapses that stack into a single Rust binary you control — git-push to deploy, automatic HTTPS via Pingora (Cloudflare's open-source proxy), built-in error tracking, and request analytics, free to self-host, with Temps Cloud — a managed add-on for telemetry retention, offsite backups, and AI credits — coming soon.
TL;DR:
bunx @temps-sdk/cli deploy my-api -b main -e production -y— your FastAPI app is live with HTTPS and monitoring in under 5 minutes. Temps is Apache 2.0, free to self-host, with no per-seat fees; Temps Cloud, a managed add-on for telemetry retention, backups, and AI credits, is coming soon.
How Do I Deploy FastAPI to Production Without DevOps?
The fastest path: push your code to a git repository, connect it to Temps, and run one CLI command. Temps detects Python projects, generates an optimized Dockerfile, builds the container, provisions a Let's Encrypt certificate, and starts routing traffic — all without you touching Nginx or Docker config.
What You'll Get
After this tutorial, your FastAPI app will have:
- Production deployment with automatic HTTPS (Let's Encrypt via Pingora proxy)
- Zero-config Python detection — Temps generates an optimized Dockerfile automatically
- Encrypted environment variable management — variables injected at runtime, never in images
- Built-in error tracking — exception capture with stack traces, no Sentry subscription needed
- Request analytics — latency, error rates, geographic distribution in your dashboard
- Auto-rollback — health checks every 5 seconds, 2 consecutive failures trigger rollback within 60 seconds
Prerequisites
- A FastAPI application
- Git repository (GitHub, GitLab, or Bitbucket)
- Python 3.9+ project with
requirements.txtorpyproject.toml
Project Structure
Temps works with any FastAPI project layout. Here's a minimal example:
my-fastapi-app/
├── main.py # or app/main.py
├── requirements.txt # or pyproject.toml
└── .env # optional, for local development only
main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello from FastAPI on Temps"}
@app.get("/health")
def health_check():
return {"status": "healthy"}
requirements.txt:
fastapi>=0.109.0
uvicorn[standard]>=0.27.0
Deploy FastAPI with the Temps CLI
Step 1: Install Temps CLI
# macOS / Linux
curl -fsSL https://temps.sh/install.sh | bash
Step 2: Login and Create Project
bunx @temps-sdk/cli login
# Create project and connect your git repository
bunx @temps-sdk/cli projects create \
-n "My FastAPI App" \
-d "FastAPI application" \
--repo your-org/your-fastapi-app \
--branch main \
--preset python
Temps automatically detects Python projects. Use --preset docker if you already have a Dockerfile.
Step 3: Deploy
bunx @temps-sdk/cli deploy my-fastapi-app -b main -e production -y
Temps will:
- Detect your FastAPI application
- Generate an optimized Dockerfile (unless you supply one)
- Build your container
- Deploy to production
- Provision an SSL certificate via Let's Encrypt
Your app is live at your-app.temps.sh within minutes.
Automatic Dockerfile Generation
You don't need Docker knowledge. Temps generates an optimized Dockerfile for your Python project:
Generated Dockerfile:
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Run with uvicorn
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
If you have a custom Dockerfile, Temps uses that instead.
Configuring Your FastAPI App
Entry Point Detection
Temps detects your FastAPI app through your project files. Common entry point patterns it handles:
main.pywithapp = FastAPI()app/main.pywithapp = FastAPI()src/main.pywithapp = FastAPI()
Custom Configuration
For custom resource limits or replica counts:
# Set CPU/memory limits and replica count
bunx @temps-sdk/cli projects config -p my-fastapi-app \
--cpu-limit 1 \
--memory-limit 512 \
--replicas 2 \
-y
Environment Variables
Adding Variables
# Single variable
bunx @temps-sdk/cli environments vars set DATABASE_URL "postgresql://..." -e production
bunx @temps-sdk/cli environments vars set OPENAI_API_KEY "sk-..." -e production
# Import from file
bunx @temps-sdk/cli environments vars import .env.production -e production
# List all (values hidden by default)
bunx @temps-sdk/cli environments vars list -e production
Accessing in FastAPI
import os
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
openai_api_key: str
debug: bool = False
settings = Settings()
Environment variables are encrypted at rest and injected at runtime — they never appear in your Docker image layers.
Database Connections
PostgreSQL
Add your database URL as an environment variable:
bunx @temps-sdk/cli environments vars set DATABASE_URL "postgresql://user:pass@host:5432/db" -e production
Use with SQLAlchemy or asyncpg:
from sqlalchemy.ext.asyncio import create_async_engine
import os
DATABASE_URL = os.getenv("DATABASE_URL")
engine = create_async_engine(DATABASE_URL)
Redis
bunx @temps-sdk/cli environments vars set REDIS_URL "redis://host:6379" -e production
import redis
import os
r = redis.from_url(os.getenv("REDIS_URL"))
MongoDB
bunx @temps-sdk/cli environments vars set MONGODB_URI "mongodb://user:pass@host:27017/db" -e production
from motor.motor_asyncio import AsyncIOMotorClient
import os
client = AsyncIOMotorClient(os.getenv("MONGODB_URI"))
Built-in Monitoring
After deployment, your Temps dashboard includes monitoring with no extra subscriptions:
Request Analytics
- Request count and latency percentiles (p50, p95, p99)
- Endpoint breakdown with per-route timing
- Error rates by route
- Geographic distribution of traffic
Error Tracking
- Exception capture with full stack traces
- Request context (headers, user, environment)
- Error grouping and trend analysis
No Sentry, no Datadog, no additional setup. It's built into the same binary that runs your proxy.
API Documentation
FastAPI's automatic documentation works out of the box on Temps:
- Swagger UI:
https://your-app.temps.sh/docs - ReDoc:
https://your-app.temps.sh/redoc
To restrict access in production:
from fastapi import FastAPI
import os
app = FastAPI(
docs_url="/docs" if os.getenv("ENABLE_DOCS") else None,
redoc_url="/redoc" if os.getenv("ENABLE_DOCS") else None,
)
Production Best Practices
Health Checks
Temps polls your health endpoint every 5 seconds. Two consecutive failures within the 60-second error window trigger automatic rollback to the last healthy deployment. Always expose a /health route:
@app.get("/health")
async def health():
# Optionally check DB connectivity here
return {"status": "healthy"}
CORS Configuration
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://yourfrontend.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Structured Logging
import logging
import json
class JSONFormatter(logging.Formatter):
def format(self, record):
return json.dumps({
"timestamp": self.formatTime(record),
"level": record.levelname,
"message": record.getMessage(),
"module": record.module,
})
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.getLogger().addHandler(handler)
Temps aggregates container stdout/stderr logs in your dashboard, searchable and streamable via bunx @temps-sdk/cli runtime-logs -p my-fastapi-app -f.
Scaling Your Application
Horizontal Scaling
Scale to multiple replicas:
bunx @temps-sdk/cli environments scale -e production -r 3
Temps handles load balancing automatically via Pingora, Cloudflare's open-source Rust proxy.
Update Resource Allocation
bunx @temps-sdk/cli projects config -p my-fastapi-app \
--cpu-limit 2 \
--memory-limit 1024 \
-y
bunx @temps-sdk/cli deploy my-fastapi-app -b main -e production -y
Custom Domains
DNS Configuration
Add an A record pointing to your Temps server IP:
| Type | Name | Value |
|---|---|---|
| A | api | YOUR_SERVER_IP |
Adding Your Domain
# HTTP-01 challenge (default, works for most domains)
bunx @temps-sdk/cli domains add -d api.yourdomain.com
# DNS-01 challenge (required for wildcard domains)
bunx @temps-sdk/cli domains add -d "*.yourdomain.com" --challenge dns-01
With --challenge dns-01, the CLI outputs a TXT record to add. Once DNS propagates, Temps completes ACME validation automatically. Let's Encrypt certificates are provisioned and renewed without manual intervention.
Comparing FastAPI Deployment Options
Temps vs Manual Docker + VPS
| Aspect | Temps | Docker + VPS manually |
|---|---|---|
| Setup time | ~5 minutes | 1–2 hours |
| Docker knowledge | Not required | Required |
| SSL setup | Automatic (Let's Encrypt) | Manual (Certbot + Nginx config) |
| Reverse proxy | Pingora (built-in) | Nginx or Caddy (manual config) |
| Error tracking | Built-in | Sentry (~$26/mo Developer plan) |
| Request analytics | Built-in | Prometheus + Grafana (manual) |
| Cost | Free to self-host (just the server you already pay for) | VPS cost only, higher ops time |
Temps vs Railway
| Aspect | Temps | Railway |
|---|---|---|
| Python detection | Automatic (Dockerfile generated) | Automatic (Nixpacks) |
| Pricing model | Free to self-host, no per-seat fees | See Railway pricing page |
| Error tracking | Built-in | Not included |
| Self-host option | Yes (Apache 2.0, free) | No |
| Vendor lock-in | None — runs on any Linux server | Proprietary platform |
| Health checks | Every 5s, auto-rollback in 60s | Health check support |
Temps vs AWS Lambda (for FastAPI via Mangum)
| Aspect | Temps | Lambda + API Gateway |
|---|---|---|
| Cold starts | None (persistent containers) | 100–500ms depending on runtime |
| Request timeout | Unlimited | 29s (API GW limit) |
| Complexity | Low — single binary | High — IAM, layers, API GW |
| Cost at scale | Predictable flat rate | Per-request variable billing |
| WebSocket/SSE | Native (Starlette) | Requires separate tooling |
Common FastAPI Patterns
Background Tasks
from fastapi import BackgroundTasks
@app.post("/send-email")
async def send_email(
email: str,
background_tasks: BackgroundTasks
):
background_tasks.add_task(send_email_task, email)
return {"message": "Email queued"}
Dependency Injection
from fastapi import Depends
async def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users")
async def get_users(db: Session = Depends(get_db)):
return db.query(User).all()
Middleware
import time
@app.middleware("http")
async def add_timing(request, call_next):
start = time.time()
response = await call_next(request)
response.headers["X-Process-Time"] = str(time.time() - start)
return response
Troubleshooting
Build Fails
Check build logs in the Temps dashboard or stream them via CLI:
bunx @temps-sdk/cli deploy my-fastapi-app -b main -e production
Common issues:
- Missing packages in
requirements.txt - Python version mismatch (specify
FROM python:3.11-slimin a custom Dockerfile) - Syntax errors caught at build time
App Crashes on Start
# Stream live logs
bunx @temps-sdk/cli runtime-logs -p my-fastapi-app -f
- Check that all required environment variables are set
- Confirm the app binds to
0.0.0.0:8000(not127.0.0.1) - Test locally with the same env vars using
pydantic-settings
Health Check Failures
Temps checks /health every 5 seconds. If your endpoint takes more than 2 seconds to respond under normal load, add a lightweight health check that bypasses slow database queries:
@app.get("/health")
async def health():
return {"status": "ok"} # Keep it fast and dependency-free
Quick Reference
# Install CLI
curl -fsSL https://temps.sh/install.sh | bash
# Login
bunx @temps-sdk/cli login
# Create project and connect repo
bunx @temps-sdk/cli projects create \
-n "My FastAPI API" \
-d "FastAPI application" \
--repo myorg/my-fastapi-app \
--branch main \
--preset python
# Deploy
bunx @temps-sdk/cli deploy my-fastapi-api -b main -e production -y
# Stream logs
bunx @temps-sdk/cli runtime-logs -p my-fastapi-api -f
# Set environment variable
bunx @temps-sdk/cli environments vars set SECRET_KEY "value" -e production
# Scale replicas
bunx @temps-sdk/cli environments scale -e production -r 3
# Add domain (HTTP-01 by default, DNS-01 for wildcards)
bunx @temps-sdk/cli domains add -d api.example.com
Ready to deploy your FastAPI app? Get started at temps.sh — self-host for free (Apache 2.0), with Temps Cloud, a managed add-on for telemetry retention, backups, and AI credits, coming soon:
curl -fsSL https://temps.sh/install.sh | bash && bunx @temps-sdk/cli login