DEV Community

Cover image for Deploying FastAPI with Aiven PostgreSQL and Docker (Production-Ready Guide)
Rose Wabere
Rose Wabere

Posted on

Deploying FastAPI with Aiven PostgreSQL and Docker (Production-Ready Guide)

PostgreSQL is a reliable database, and FastAPI has emerged as one of the most popular frameworks for creating high-performance APIs. However, maintaining your own Postgres instance can be a distraction when it comes time to deploy. This is where the managed cloud database service Aiven comes into play. It takes away infrastructure issues and gives you complete access to PostgreSQL, making operations much less painful.

In this tutorial, I'll walk you through setting up a FastAPI project, connecting it to Aiven PostgreSQL with asyncpg, and containerizing everything with Docker for both development and production. Along the way, you'll discover how each component fits into a contemporary backend stack and the reasons these tools are frequently used together.

Requirements:

  • Python 3.9+
  • Docker & Docker Compose (for reproducible environments and easy deployment)
  • An Aiven account (free tier works and is enough for testing)
  • Basic familiarity with FastAPI and async/await (understanding non-blocking I/O will help)

Step 1: FastAPI Project Setup

Create a new project folder and set up a virtual environment:

mkdir myfastapi && cd myfastapi
python -m venv venv
source venv/bin/activate
Enter fullscreen mode Exit fullscreen mode

Install dependencies:

# requirements.txt
fastapi
uvicorn[standard]
asyncpg
python-dotenv
gunicorn
email-validator
python-multipart
Enter fullscreen mode Exit fullscreen mode

Here’s what these packages do:

  • FastAPI - the web framework
  • uvicorn - ASGI server for running FastAPI
  • asyncpg - high-performance async PostgreSQL driver
  • python-dotenv - loads environment variables from .env
  • gunicorn - production-grade process manager
  • others → useful utilities for forms and validation

Now, a minimal FastAPI app with a health check and a database test endpoint:

# app/main.py
from fastapi import FastAPI
import asyncpg
import os

app = FastAPI()

DATABASE_URL = os.getenv("DATABASE_URL")

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

@app.get("/db-check")
async def db_check():
    conn = await asyncpg.connect(DATABASE_URL)
    version = await conn.fetchval("SELECT version()")
    await conn.close()
    return {"postgres_version": version}
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • A basic API endpoint (/)
  • A real database connection (/db-check)
  • Async database access using await, which allows FastAPI to handle many requests efficiently without blocking

Step 2: Configure Aiven PostgreSQL

  1. Log in to Aiven Console, create a new PostgreSQL service (choose your cloud provider and region).
  2. Once the service is running, go to the Overview tab and copy the Service URI. It will look like:
postgres://avnadmin:password@host:port/defaultdb?sslmode=require
Enter fullscreen mode Exit fullscreen mode
  1. Important: For asyncpg, the URI must use the postgresql+asyncpg:// scheme. Adjust it to:
postgresql+asyncpg://avnadmin:password@host:port/defaultdb?sslmode=require
Enter fullscreen mode Exit fullscreen mode

This tells your app to use the asyncpg driver instead of the default PostgreSQL driver.

Save this as DATABASE_URL in a .env file (but remember, never commit it!).

Step 3: Dockerize the App

Create a Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Enter fullscreen mode Exit fullscreen mode

Docker lets you package your app with all its dependencies into a container, ensuring:

  • consistent behavior across environments
  • easy deployment to cloud platforms
  • no “works on my machine” issues

Build the image: docker build -t myfastapi .

Step 4: Docker Compose for Development

docker-compose.yml (dev version):

version: "3.9"
services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: ${DATABASE_URL}
    volumes:
      - ./app:/app/app   # live reload for code changes
    command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
Enter fullscreen mode Exit fullscreen mode

Key ideas here:

  • Volumes allow live code updates without rebuilding the container
  • --reload enables hot-reloading for faster development
  • Environment variables keep secrets out of your code

Run with: docker compose --env-file .env up

Step 5: Running SQL Scripts on Aiven

Since we are not using a local database container, we execute scripts directly against Aiven using psql:

psql "$DATABASE_URL" < scripts/01_create_tables.sql
Enter fullscreen mode Exit fullscreen mode

What this approach does:

  • treats Aiven as your single source of truth
  • avoids environment drift between local and production
  • is closer to how real production systems are managed

Make sure your DATABASE_URL in the shell uses the postgresql://scheme (without +asyncpg) for psql.

Step 6: Docker Compose for Production

Create docker-compose.prod.yml:

version: "3.9"
services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: ${DATABASE_URL}
    command: gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app --bind 0.0.0.0:8000
    restart: always
Enter fullscreen mode Exit fullscreen mode

Differences from development:

  • No volume mounts (immutable containers)
  • Uses Gunicorn for better process management
  • Multiple workers for handling concurrent traffic

Run in detached mode:

docker compose --env-file .env.production -f docker-compose.prod.yml up -d
Enter fullscreen mode Exit fullscreen mode

Step 7: Environment Variables & Security

Never commit .env files. Use .env.example as a template.

In production, inject secrets via your CI/CD or orchestration tool.

Always use sslmode=require with Aiven to enforce encrypted connections.

Conclusion

You now have a FastAPI app running with a managed PostgreSQL database, fully containerized and ready for production. This setup lets you focus on writing code while Aiven handles the database heavy lifting.

If you found this helpful, give it a ❤️ and share it with your network.

Top comments (0)