Skip to main content

FastAPI Cloud Deployment

Introduction

Deploying your FastAPI application to the cloud is a crucial step in making your API accessible to users worldwide. Cloud deployment offers many benefits, including scalability, reliability, and often simplified maintenance compared to self-hosted solutions.

In this guide, we'll cover how to deploy your FastAPI application to several popular cloud platforms, each with its own advantages and use cases. Whether you're looking for a free tier to host a personal project or a robust solution for enterprise applications, there's a cloud provider that fits your needs.

Prerequisites

Before proceeding with cloud deployment, ensure you have:

  1. A working FastAPI application that runs locally
  2. Your application's dependencies listed in a requirements.txt file
  3. A basic understanding of Docker (recommended for some deployment options)
  4. Accounts set up with your chosen cloud provider(s)

Preparing Your FastAPI Application for Deployment

1. Create a Production-Ready Entry Point

First, let's make sure your FastAPI application has a proper entry point. Create a file named main.py (if you haven't already):

python
from fastapi import FastAPI
import uvicorn

app = FastAPI(title="My API Service")

@app.get("/")
async def root():
return {"message": "Hello World"}

@app.get("/health")
async def health_check():
return {"status": "healthy"}

# Only for development:
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

2. Set Up a Procfile (for Heroku and similar platforms)

Create a file named Procfile (without any file extension):

web: uvicorn main:app --host=0.0.0.0 --port=${PORT:-8000}

3. Create a Requirements File

Ensure your requirements.txt includes all your dependencies:

fastapi>=0.68.0
uvicorn>=0.15.0
gunicorn>=20.1.0
# Add other dependencies your app needs

4. Create a Dockerfile (for container-based deployments)

dockerfile
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Cloud Deployment Options

Let's explore how to deploy your FastAPI application to various cloud platforms.

1. Heroku Deployment

Heroku provides one of the simplest ways to deploy FastAPI applications, especially for beginners.

Steps for Heroku Deployment:

  1. Install the Heroku CLI and log in:
bash
# Install Heroku CLI (instructions vary by OS)
heroku login
  1. Create a new Heroku app:
bash
heroku create your-fastapi-app-name
  1. Deploy your application:
bash
git add .
git commit -m "Ready for deployment"
git push heroku main
  1. Open your application:
bash
heroku open

Monitoring your application:

bash
heroku logs --tail

Key Benefits of Heroku:

  • Simple deployment process
  • Free tier available for testing
  • Automatic HTTPS configuration
  • Easy integration with databases and other add-ons

2. AWS Elastic Beanstalk

AWS Elastic Beanstalk provides a powerful yet relatively simple way to deploy FastAPI applications on AWS infrastructure.

Steps for AWS Elastic Beanstalk Deployment:

  1. Install the AWS EB CLI:
bash
pip install awsebcli
  1. Initialize your EB project:
bash
eb init -p python-3.8 your-fastapi-app-name
  1. Create an environment and deploy:
bash
eb create your-environment-name
  1. Open your application:
bash
eb open

Configuration:

Create a file named .ebextensions/01_fastapi.config:

yaml
option_settings:
aws:elasticbeanstalk:container:python:
WSGIPath: main:app
aws:elasticbeanstalk:environment:proxy:
ProxyServer: nginx

Key Benefits of AWS Elastic Beanstalk:

  • Scalability with auto-scaling groups
  • Integration with other AWS services
  • Production-grade infrastructure
  • Monitoring and health checks

3. Google Cloud Run

Google Cloud Run is a fully managed compute platform that runs stateless containers. It's an excellent choice for FastAPI applications.

Steps for Google Cloud Run Deployment:

  1. Install the Google Cloud SDK and authenticate:
bash
# Install Google Cloud SDK (instructions vary by OS)
gcloud auth login
  1. Build and push your Docker container:
bash
gcloud builds submit --tag gcr.io/YOUR-PROJECT-ID/fastapi-app
  1. Deploy to Cloud Run:
bash
gcloud run deploy fastapi-service \
--image gcr.io/YOUR-PROJECT-ID/fastapi-app \
--platform managed \
--allow-unauthenticated \
--region us-central1

Key Benefits of Google Cloud Run:

  • Pay-per-use pricing (only pay for what you use)
  • Automatic scaling to zero when not in use
  • Managed HTTPS
  • Seamless container deployment

4. Azure App Service

Microsoft Azure's App Service is another excellent platform for hosting FastAPI applications.

Steps for Azure App Service Deployment:

  1. Install Azure CLI and log in:
bash
# Install Azure CLI (instructions vary by OS)
az login
  1. Create an App Service plan and web app:
bash
az appservice plan create --name fastapi-app-plan --resource-group your-resource-group --sku B1
az webapp create --name your-fastapi-app --plan fastapi-app-plan --resource-group your-resource-group --runtime "PYTHON|3.8"
  1. Configure the startup command:
bash
az webapp config set --name your-fastapi-app --resource-group your-resource-group --startup-file "gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app"
  1. Deploy using Git:
bash
az webapp deployment source config-local-git --name your-fastapi-app --resource-group your-resource-group
git remote add azure <git-url-from-previous-command>
git push azure main

Key Benefits of Azure App Service:

  • Integration with Azure ecosystem
  • Easy scaling options
  • Built-in security and compliance features
  • Support for custom domains and SSL

5. Deta.sh (Free Platform for Small Applications)

Deta is a free cloud platform that's perfect for small FastAPI applications and personal projects.

Steps for Deta Deployment:

  1. Install Deta CLI:
bash
curl -fsSL https://get.deta.dev/cli.sh | sh
  1. Login and deploy:
bash
deta login
deta new --python fastapi-app
  1. Update your main.py file to work with Deta:
python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
return {"message": "Hello World from Deta!"}

Key Benefits of Deta:

  • Completely free
  • Super simple deployment
  • Good for personal projects and prototypes
  • No infrastructure management needed

Best Practices for Cloud Deployment

1. Environment Variables

Always use environment variables for configuration and secrets:

python
import os
from fastapi import FastAPI

app = FastAPI()
DATABASE_URL = os.getenv("DATABASE_URL")
API_KEY = os.getenv("API_KEY")

@app.get("/")
async def root():
return {"message": "Using environment variables"}

2. Health Checks

Implement a health check endpoint to monitor your application's status:

python
@app.get("/health")
async def health_check():
# You can add database connectivity checks or other service checks here
return {
"status": "healthy",
"version": "1.0.0"
}

3. Logging

Configure proper logging for production:

python
import logging
from fastapi import FastAPI, Request
import time

app = FastAPI()

# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)
logger = logging.getLogger(__name__)

@app.middleware("http")
async def log_requests(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
logger.info(f"{request.method} {request.url.path} {response.status_code} {process_time:.3f}s")
return response

4. Database Connections

Ensure your database connections are properly handled for cloud environments:

python
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import os

DATABASE_URL = os.getenv("DATABASE_URL")

# Add connection pooling configuration for cloud environments
engine = create_engine(
DATABASE_URL,
pool_size=5, # Adjust based on your needs
max_overflow=10,
pool_recycle=300 # Recycle connections every 5 minutes
)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

Handling Scaling in Cloud Environments

One of the biggest advantages of cloud deployment is the ability to scale your application as demand increases.

Stateless Design

Ensure your FastAPI application is stateless, meaning it doesn't store session data locally:

python
from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware
import redis
import os

app = FastAPI()

# Use external session store like Redis
redis_client = redis.Redis(
host=os.getenv("REDIS_HOST", "localhost"),
port=os.getenv("REDIS_PORT", 6379),
password=os.getenv("REDIS_PASSWORD", "")
)

# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, specify exact origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

# Use external session store
async def get_session_data(session_id: str):
data = redis_client.get(f"session:{session_id}")
return data

@app.get("/user-data")
async def user_data(session_data=Depends(get_session_data)):
return {"user_data": session_data}

Real-World Example: Deploying a FastAPI Todo API

Let's put everything together with a complete example of deploying a Todo API to the cloud.

1. Complete API Code (main.py)

python
import os
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from typing import List, Optional
import databases
import sqlalchemy

# Get database URL from environment variable
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./test.db")

database = databases.Database(DATABASE_URL)

metadata = sqlalchemy.MetaData()

todos = sqlalchemy.Table(
"todos",
metadata,
sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column("title", sqlalchemy.String),
sqlalchemy.Column("description", sqlalchemy.String),
sqlalchemy.Column("completed", sqlalchemy.Boolean),
)

engine = sqlalchemy.create_engine(
DATABASE_URL, connect_args={"check_same_thread": False}
)
metadata.create_all(engine)

app = FastAPI(title="Todo API")

class TodoIn(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False

class Todo(TodoIn):
id: int

@app.on_event("startup")
async def startup():
await database.connect()

@app.on_event("shutdown")
async def shutdown():
await database.disconnect()

@app.get("/todos/", response_model=List[Todo])
async def read_todos():
query = todos.select()
return await database.fetch_all(query)

@app.post("/todos/", response_model=Todo)
async def create_todo(todo: TodoIn):
query = todos.insert().values(
title=todo.title,
description=todo.description,
completed=todo.completed
)
last_record_id = await database.execute(query)
return {**todo.dict(), "id": last_record_id}

@app.get("/todos/{todo_id}", response_model=Todo)
async def read_todo(todo_id: int):
query = todos.select().where(todos.c.id == todo_id)
todo = await database.fetch_one(query)
if not todo:
raise HTTPException(status_code=404, detail="Todo not found")
return todo

@app.put("/todos/{todo_id}", response_model=Todo)
async def update_todo(todo_id: int, todo: TodoIn):
query = todos.update().where(todos.c.id == todo_id).values(
title=todo.title,
description=todo.description,
completed=todo.completed
)
await database.execute(query)
return {**todo.dict(), "id": todo_id}

@app.delete("/todos/{todo_id}")
async def delete_todo(todo_id: int):
query = todos.delete().where(todos.c.id == todo_id)
await database.execute(query)
return {"message": "Todo deleted successfully"}

@app.get("/health")
async def health_check():
return {"status": "healthy", "database": "connected"}

2. Requirements File (requirements.txt)

fastapi==0.95.0
uvicorn==0.21.1
databases==0.7.0
SQLAlchemy==2.0.9
aiosqlite==0.17.0

3. Docker Deployment (Dockerfile)

dockerfile
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Create a non-root user
RUN adduser --disabled-password --gecos "" appuser
USER appuser

# Command to run when the container starts
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

4. Docker Compose for Local Testing (docker-compose.yml)

yaml
version: '3'

services:
api:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/todos
depends_on:
- db

db:
image: postgres:13
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=postgres
- POSTGRES_DB=todos
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:

Testing the Deployment

After deploying your FastAPI application to the cloud, you should test it to ensure everything works correctly.

1. Basic Tests with cURL

bash
# Test the health endpoint
curl https://your-deployed-app.com/health

# Create a new todo
curl -X POST -H "Content-Type: application/json" \
-d '{"title": "Learn FastAPI", "description": "Deploy to the cloud"}' \
https://your-deployed-app.com/todos/

# Get all todos
curl https://your-deployed-app.com/todos/

2. Interactive Testing with Swagger UI

FastAPI automatically generates interactive documentation. Visit:

https://your-deployed-app.com/docs

From there, you can interactively test all your API endpoints.

Troubleshooting Common Deployment Issues

1. Application Fails to Start

Symptom: Your application doesn't start in the cloud environment.

Solutions:

  • Check logs using the cloud provider's logging interface
  • Verify your entry point configuration (Procfile, Docker CMD, etc.)
  • Make sure all dependencies are in requirements.txt
  • Check if your cloud provider restricts certain ports

2. Database Connection Issues

Symptom: Your application starts but can't connect to the database.

Solutions:

  • Verify environment variables are correctly set
  • Check network settings (firewalls, security groups)
  • Make sure your database service is running
  • Check connection string format

3. Performance Issues

Symptom: Slow response times in the cloud.

Solutions:

  • Check resource allocation (memory, CPU)
  • Optimize database queries
  • Consider using connection pooling
  • Add caching for frequently accessed data

Summary

In this guide, we've explored how to deploy FastAPI applications to various cloud platforms, including Heroku, AWS Elastic Beanstalk, Google Cloud Run, Azure App Service, and Deta.

We've covered:

  • Preparing your FastAPI application for cloud deployment
  • Step-by-step deployment procedures for different cloud providers
  • Best practices for secure and scalable cloud deployments
  • A real-world example of a Todo API deployment
  • Testing and troubleshooting your deployed application

Cloud deployment enables you to share your API with users worldwide while ensuring reliability, scalability, and security. Choose the platform that best meets your needs based on factors like budget, traffic expectations, and required integrations.

Additional Resources

Exercises

  1. Deploy the Todo API to a free tier of a cloud provider of your choice.
  2. Modify the Todo API to use a cloud-hosted database instead of SQLite.
  3. Add authentication to your API and deploy the updated version.
  4. Set up a CI/CD pipeline to automatically deploy your API when you push changes to GitHub.
  5. Configure monitoring and alerts for your deployed application.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)