Deployment
Containerize with Docker, add health checks, and implement graceful shutdown.
My API works on my machine. How do I get it running in the cloud?
With Docker. A Dockerfile describes exactly how to build and run your app. Anyone (or any server) with Docker can run it identically:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Line by line: start from a Python image, install dependencies, copy your code, run uvicorn. The --host 0.0.0.0 is critical — it means "listen on all network interfaces" so the container is reachable from outside.
What's a health check and why do I need one?
A health check endpoint tells the deployment platform your app is alive and ready. Platforms like Railway and AWS check it periodically and restart your app if it stops responding:
from datetime import datetime
startup_time = datetime.utcnow()
@app.get("/health")
def health():
return {
"status": "healthy",
"uptime_seconds": (datetime.utcnow() - startup_time).total_seconds(),
"version": "1.0.0"
}
Keep it simple — no database calls, no external dependencies. The health check should test that your app process is running, not that every downstream service is up.
What's graceful shutdown?
When the platform sends a shutdown signal (SIGTERM), your app should finish processing current requests before exiting — not cut them off mid-response:
import signal
import asyncio
def handle_shutdown(signum, frame):
print("Shutting down gracefully...")
# FastAPI/uvicorn handle this automatically with --timeout-graceful-shutdown
signal.signal(signal.SIGTERM, handle_shutdown)
Uvicorn handles most of this for you. The key setting is --timeout-graceful-shutdown 30 — it gives in-flight requests 30 seconds to complete before forcing a shutdown.
What about the requirements.txt? How do I make sure production has the same packages?
Pin exact versions:
fastapi==0.110.0
uvicorn==0.27.0
pydantic==2.6.0
pydantic-settings==2.1.0
Never use fastapi>=0.110.0 in production — an unpinned dependency could update and break your app. Use pip freeze > requirements.txt to capture exact versions from your working environment.
The deployment flow: push code, Docker builds the image, the platform runs the container, health checks confirm it's alive. If the health check fails, the platform rolls back to the previous version automatically.
Practice your skills
Sign up to write and run code in this lesson.
Deployment
Containerize with Docker, add health checks, and implement graceful shutdown.
My API works on my machine. How do I get it running in the cloud?
With Docker. A Dockerfile describes exactly how to build and run your app. Anyone (or any server) with Docker can run it identically:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Line by line: start from a Python image, install dependencies, copy your code, run uvicorn. The --host 0.0.0.0 is critical — it means "listen on all network interfaces" so the container is reachable from outside.
What's a health check and why do I need one?
A health check endpoint tells the deployment platform your app is alive and ready. Platforms like Railway and AWS check it periodically and restart your app if it stops responding:
from datetime import datetime
startup_time = datetime.utcnow()
@app.get("/health")
def health():
return {
"status": "healthy",
"uptime_seconds": (datetime.utcnow() - startup_time).total_seconds(),
"version": "1.0.0"
}
Keep it simple — no database calls, no external dependencies. The health check should test that your app process is running, not that every downstream service is up.
What's graceful shutdown?
When the platform sends a shutdown signal (SIGTERM), your app should finish processing current requests before exiting — not cut them off mid-response:
import signal
import asyncio
def handle_shutdown(signum, frame):
print("Shutting down gracefully...")
# FastAPI/uvicorn handle this automatically with --timeout-graceful-shutdown
signal.signal(signal.SIGTERM, handle_shutdown)
Uvicorn handles most of this for you. The key setting is --timeout-graceful-shutdown 30 — it gives in-flight requests 30 seconds to complete before forcing a shutdown.
What about the requirements.txt? How do I make sure production has the same packages?
Pin exact versions:
fastapi==0.110.0
uvicorn==0.27.0
pydantic==2.6.0
pydantic-settings==2.1.0
Never use fastapi>=0.110.0 in production — an unpinned dependency could update and break your app. Use pip freeze > requirements.txt to capture exact versions from your working environment.
The deployment flow: push code, Docker builds the image, the platform runs the container, health checks confirm it's alive. If the health check fails, the platform rolls back to the previous version automatically.
Practice your skills
Sign up to write and run code in this lesson.