Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
FREEDOM251

Freedom251 › Blog › Alembic

How to Use FastAPI With a Relational Database on Ubuntu

By Freedom251 Team · · 11 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The most maintainable way to connect a FastAPI application to PostgreSQL on Ubuntu is to install PostgreSQL with apt, create a least-privilege database role, isolate your Python dependencies in a virtual environment, and use SQLAlchemy with Alembic migrations. Choose a synchronous stack (psycopg2 and regular def endpoints) for the simplest implementation, or an asynchronous stack (asyncpg, SQLAlchemy’s asyncio extension, and async def endpoints) when your application benefits from non-blocking database I/O.

This guide builds both options, explains where they differ, and shows how to keep credentials out of source code, generate schema migrations, inject sessions into routes, and diagnose the failures that are most common on Ubuntu.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the FastAPI–PostgreSQL stack contains

FastAPI is the HTTP framework, PostgreSQL is the relational database, SQLAlchemy is the database toolkit and object-relational mapper, and Alembic tracks changes to your schema. A PostgreSQL driver translates SQLAlchemy operations into the wire protocol PostgreSQL understands.

Layer Typical choice Purpose
API framework FastAPI Routing, validation, dependency injection and OpenAPI documentation.
ORM/toolkit SQLAlchemy 2.x Models, queries, transactions and connection pooling.
Migration tool Alembic Versioned, repeatable schema changes.
Database driver psycopg2 for synchronous code; asyncpg for asynchronous code Connects Python to PostgreSQL.
Database server PostgreSQL on Ubuntu Durable relational storage, constraints, indexes and transactions.

FastAPI’s official SQL tutorial uses SQLModel, which combines SQLAlchemy and Pydantic. It demonstrates SQLite, but the same SQLAlchemy-compatible approach can use PostgreSQL. FastAPI release notes identify version 0.115.1, released on 12 October 2024, as the release that added that SQLModel-based database tutorial. SQLAlchemy’s current documented line is 2.x; pin the versions you deploy rather than copying unverified version numbers from an old tutorial.

#1 Best Overall
Sale
TOZO A1 Wireless Earbuds Bluetooth 5.3 Light Weight in Ear Headphones | IPX5 Waterproof,2 Mics for AI Calls,Immersive Premium Sound Bass Headset with Charging Case,32 EQ via App Black
  • [Ultra-Lightweight Ear Buds Designed for Small Ears] Each earbud weighs only 3.7g and features a compact, ergonomic in-ear design made especially for small ears. Secure, low-profile, and comfortable for workouts, all-day wear or overnight sleeping.The ultra-slim profile sits flush in your ear with no hard edges poking or rubbing, so you can even sleep on your side without discomfort.
  • [Immersive Stereo Sound with TOZO OrigX Technology] TOZO OrigX tuning delivers clear vocals, balanced mids, and natural stereo sound for music, podcasts, and videos.
  • [Long Battery Life for Daily Use] Get up to 7 hours of playtime on a single charge, with up to 32 hours total using the charging case—ideal for workdays, commuting, and extended listening sessions.
  • [Bluetooth 5.3 & Stable Connection] Bluetooth 5.3 provides fast pairing, stable wireless performance, and reduced dropouts as you move around home or office.
  • [Deep Bass with Clear Vocals] High-performance drivers produce punchy bass while keeping vocals clean and detailed for everyday listening.

Choose synchronous or asynchronous database access

Both designs are valid. The important rule is consistency: use a synchronous driver with synchronous sessions and route functions, or an asynchronous driver with asynchronous sessions and route functions.

Decision point Synchronous stack Asynchronous stack
Install sqlalchemy, psycopg2-binary sqlalchemy[asyncio], asyncpg
URL scheme postgresql:// (SQLAlchemy selects the psycopg2 driver when installed) postgresql+asyncpg://
Route style def async def with awaited database calls
Session class Session and sessionmaker AsyncSession and async_sessionmaker
Migrations Use the same synchronous URL Alembic’s runner is synchronous; configure a synchronous migration URL, commonly by removing +asyncpg and using psycopg2.
Operational trade-off Fewer moving parts and easier debugging Non-blocking I/O, but every database operation and transaction must be awaited correctly.

Start synchronously unless you have a clear reason to make the database layer asynchronous. An async endpoint that calls a synchronous database session can still block the event loop, while an async stack adds a second connection URL for migrations and more lifecycle details.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install PostgreSQL on Ubuntu

Use Ubuntu’s packaged PostgreSQL

Ubuntu’s server documentation recommends the distribution package and notes that it is configured with usable defaults:

sudo apt update
sudo apt install postgresql
sudo systemctl status postgresql

The exact PostgreSQL major version depends on your Ubuntu release. Ubuntu ships one fixed major version in each release. Check what was installed before relying on version-specific behavior:

psql --version
sudo -u postgres psql -c "SHOW server_version;"

Install a newer major version with PGDG

If your application requires a newer major release than Ubuntu provides, use the PostgreSQL project’s APT repository (PGDG). Its instructions describe adding the repository and installing versioned packages such as postgresql-18. The available major versions and supported Ubuntu releases change, so follow the current PGDG instructions for your release instead of hard-coding an old repository line. The PostgreSQL Linux download documentation also provides Ubuntu-specific package guidance.

Do not mix arbitrary packages from several repositories. Decide which repository owns the server version, install the matching client and server packages, and verify the resulting service and psql version.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Smart Watch for Men Women Compatible with iPhone Samsung Android Phone 1.69 inch Full Touch Screen IP68 Waterproof Bluetooh Fitness Tracker Heart Rate/Sleep Monitor (Black)
  • 【IP68 Waterproof Multifunctinal Smart Watch】Torjalph fitness activity tracker smart watch is IP68 waterproof technology ,you can wear it when swimming,handwashing,it's rain-proof which means that you perform multiple exercise modes outside without worrying about sweat or rain corroding your fitness smart watch,and this watch equipped with a 230 mAh large capacity battery magnetic charging ,and this sports activity tracker watch can be used 5-7 days If fully charged.
  • 【Larger 1.83'' Full Screen Watch & Multi-dial Selection】1.83 inch full HD color touch screen smart watch for men / women provides excellent 240*284 resolution image quality ,This Bluetooth smart watch offers a better touch experience and remarkable immersion and ,more than 200 watch faces for you to choose from App"Da Fit ", you can change the dial style according to your mood to wear keeping the world on your wrist
  • 【Accurate Activity Tracker Smart Watch 】sports watch activity tracker uses sweat and dust resistant breathable silicone strap, our Fitness Tracker Smart Watch for Android iOS Phones supports 12 sports modes,walking,running,bicycle,swimming,badminton,basketball,football,rope skipping. This bluetooth calls smart watch for men women is lightweight and stylish, bringing more convenient and relaxing sports experience while also providing more protection.
  • 【Your 24 Hour Personal Daily Health Monitor】Fitness watch for women men full touch screen IP67 waterproof bluetooth smartwatch for Android iOS Phones with heart rate blood pressure monitor multifunction Andriod smart watch with steps counter sleep monitor sports fitness watch, monitoring blood oxygen saturation allows you to understand your physical condition in real time to track fitness progress ,to know your health status in time.
  • 【More Functions Bluetooth Call Smart Watch】This fitness activity smart watch full screen for iPhone and Android phones includes a bunch of new features including:The bluetooth smart watch can hang up the phone, receive and display WhatsAPP /Text /Facebook /Twitter /Messenger reminder.Support sedentary reminder, alarm clock, stopwatch, timer,weather information,music control, remote camera control compatible with Android 5.0 and above or iOS 9.0 and above smartphones.

Create a database and an application role

Ubuntu’s package normally creates a local operating-system user and PostgreSQL superuser named postgres. Use that account only for administration. Create a separate login for the FastAPI application and a database it owns.

sudo -u postgres psql

At the psql prompt, run commands like these, replacing the example names and password with values appropriate for your project:

CREATE ROLE fastapi_app WITH LOGIN PASSWORD 'replace-with-a-long-random-password';
CREATE DATABASE fastapi_db OWNER fastapi_app;
c fastapi_db
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
GRANT USAGE, CREATE ON SCHEMA public TO fastapi_app;
q

For local development, PostgreSQL commonly listens on localhost:5432. A production deployment may use a managed or separate database host, TLS, firewall rules and a different port. Never commit the password, put it in shell history, or grant the application superuser privileges.

Create the FastAPI project and install dependencies

Set up an isolated environment

mkdir fastapi-postgres
cd fastapi-postgres
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

Install the synchronous baseline:

pip install fastapi uvicorn sqlalchemy alembic psycopg2-binary

For the asynchronous variant, install the asyncio extra and driver instead:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
pip install fastapi uvicorn "sqlalchemy[asyncio]" alembic asyncpg

Record the resolved dependency set so another machine does not silently receive incompatible versions:

pip freeze > requirements.txt

For a team or deployment pipeline, maintain explicit version pins in a reviewed requirements file and update them deliberately. FastAPI, SQLAlchemy, Alembic, PostgreSQL and Ubuntu all evolve independently.

Rank #3
New Bee Guitar Cable 10ft Electric Instrument Bass AMP Cord
  • [Low Noise High Fidelity] New bee guitar cord with 22AWG oxygen-free-copper center conductors provides enhanced signal transfer, the PVC insulation material and the high-density stranded copper double shield provide noise rejection for quiet operation
  • [Ideal for Choice] New bee 1/4 straight and right angle metal connectors, ensures a secure connection in any instrument, pedal, or amp jack. L shape great fro on stage guitar stands
  • [Wide Compatible] Suitable for mixer, power amplifier, microphone, effector, decoder, equalizer, electoronic organ, electric guitar, electric bass and other electronic equipments. Widely used in the installation of smart home, karaoke speaker, professional stage audio, etc
  • [Easy Disassemble] Making incidental repairs quick and easy! Very nice, flexible cable
  • [Dont Hesite to Order] 24 hours customer services and professional technology team are standing by

Keep the connection string outside source code

Set a development variable in your shell or a local environment file that is excluded from version control:

export DATABASE_URL='postgresql+psycopg2://fastapi_app:replace-with-a-long-random-password@localhost:5432/fastapi_db'

The async URL is:

export DATABASE_URL='postgresql+asyncpg://fastapi_app:replace-with-a-long-random-password@localhost:5432/fastapi_db'

In production, inject the variable through the service manager or secret store. If the password contains characters such as @, : or /, URL-encode it or construct the URL with SQLAlchemy’s URL helper rather than creating an invalid string.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build a synchronous SQLAlchemy database layer

Create database.py with one engine, a session factory and a declarative base. The pool_pre_ping option lets SQLAlchemy test an idle connection before using it, which helps after a server restart.

import os
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, sessionmaker

DATABASE_URL = os.environ["DATABASE_URL"]

engine = create_engine(
    DATABASE_URL,
    pool_pre_ping=True,
)

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

class Base(DeclarativeBase):
    pass

Define a model in models.py. SQLAlchemy 2.x’s typed declarative style makes columns explicit:

from sqlalchemy import String, Text
from sqlalchemy.orm import Mapped, mapped_column
from .database import Base

class Article(Base):
    __tablename__ = "articles"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column(String(200), nullable=False)
    body: Mapped[str] = mapped_column(Text, nullable=False)

The model describes the desired table; it does not automatically update an existing production database. Use Alembic, described below, to apply the schema change.

Inject and close a session per request

A generator dependency opens a session, yields it to the route, and closes it even when the request raises an exception:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
BSIMB 15.6" Digital Family Calendar & Chore Chart, No Subscription Fees
  • Digital Family Calendar: BSIMB digital calendar wall touch screen puts an end to your chaotic life. Designed for busy families, the digital calendar keeps you organised and in step with your family. Assign different colours and tasks to each family member to make family scheduling easier and more intuitive.
  • Easy Setup and Auto-Sync: Plug in, connect to WLAN and auto-syn your electric calendar in minutes. Digital wall calendar compatible with Google calendar, iCloud calendar, Outlook calendar, Cozi calendar and Yahoo calendar. Add events directly on the device or through the ecalendar app. Electronic calendar stays current whether you're at work or traveling—no manual updates needed.
  • All-In-One Home Assistant: Smart calendar builds habits and encourage independence with personalised chores. Display daily meal plan to reduce the daily ‘What's for dinner?’ stress. To-do lists keep track of everything you want. Turning chores into valuable achievements with stars and rewards, making life easier and more enjoyable.
  • Manage Anytime Anywhere: BSIMB electronic calendar for family stay connected with the powerful ecalendar app. Access and manage your digital wall calendar anytime, anywhere with free features like stars & rewards, photo screensaver, chore charts, meals plans, to-do lists etc. Electronic planner paid features like Magic Import tailor advanced tools for users with special needs.
  • Stay in Touch with Loved Ones: Share photos or videos from your phone to electronic wall calendar with app, instantly update your life moment, and keep in touch with your family, especially those who are far away; you can also surprise your smart calendar digital wall by sending him a wish card; it's also great for keeping tech-illiterate elders in touch with the youngsters.
from collections.abc import Generator
from sqlalchemy.orm import Session
from .database import SessionLocal

def get_db() -> Generator[Session, None, None]:
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Use Pydantic models for request and response validation in schemas.py:

from pydantic import BaseModel, ConfigDict

class ArticleCreate(BaseModel):
    title: str
    body: str

class ArticleRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    title: str
    body: str

Then wire the dependency into main.py:

from fastapi import Depends, FastAPI
from sqlalchemy import select
from sqlalchemy.orm import Session

from .database import Base, engine, get_db
from .models import Article
from .schemas import ArticleCreate, ArticleRead

app = FastAPI()

@app.post("/articles", response_model=ArticleRead)
def create_article(payload: ArticleCreate, db: Session = Depends(get_db)):
    article = Article(title=payload.title, body=payload.body)
    db.add(article)
    db.commit()
    db.refresh(article)
    return article

@app.get("/articles", response_model=list[ArticleRead])
def list_articles(db: Session = Depends(get_db)):
    return db.scalars(select(Article).order_by(Article.id)).all()

Commit only after all required writes for the request have succeeded. If a transaction fails, call rollback() before attempting another operation with that session. Keep transaction boundaries in application code rather than relying on implicit, long-lived sessions.

Build the asynchronous SQLAlchemy variant

The async version uses an async engine and session factory. Every database operation that performs I/O is awaited.

import os
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase

DATABASE_URL = os.environ["DATABASE_URL"]

engine = create_async_engine(
    DATABASE_URL,
    pool_pre_ping=True,
)

SessionLocal = async_sessionmaker(
    bind=engine,
    class_=AsyncSession,
    expire_on_commit=False,
)

class Base(DeclarativeBase):
    pass

async def get_db():
    async with SessionLocal() as db:
        yield db

Use the same model declarations, importing the async base from your database module. An async route might look like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from fastapi import Depends, FastAPI
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from .database import get_db
from .models import Article
from .schemas import ArticleCreate, ArticleRead

app = FastAPI()

@app.post("/articles", response_model=ArticleRead)
async def create_article(payload: ArticleCreate, db: AsyncSession = Depends(get_db)):
    article = Article(title=payload.title, body=payload.body)
    db.add(article)
    await db.commit()
    await db.refresh(article)
    return article

@app.get("/articles", response_model=list[ArticleRead])
async def list_articles(db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(Article).order_by(Article.id))
    return result.scalars().all()

Do not pass an AsyncSession to synchronous code or call synchronous methods without the required await. Also avoid sharing one session between concurrent tasks; create a session for each request or unit of work.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Configure Alembic migrations

Initialize the migration directory

From the project root, create Alembic’s configuration and script directory:

alembic init alembic

Set the database URL used by Alembic. You can put a development value in alembic.ini, but an environment variable is safer. In alembic/env.py, import your model metadata and assign it to target_metadata:

from your_package.database import Base
from your_package import models  # ensures model classes are imported

target_metadata = Base.metadata

Replace your_package with the actual Python package name. Importing the models matters: if a model has not been imported, it is absent from Base.metadata and autogenerate cannot see it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Generate and apply a revision

After the model exists and Alembic can connect, generate a candidate migration:

alembic revision --autogenerate -m "create articles table"
alembic upgrade head

Open the generated revision and review it before applying it. Autogenerate detects many table, column and index changes, but it cannot infer every semantic change safely; data transformations, renames and destructive operations often need hand-written migration code. Check the current state with:

alembic current
alembic history

When changing a model later, generate another revision, inspect its upgrade() and downgrade() functions, and apply it in a controlled deployment. Do not use Base.metadata.create_all() as a substitute for migrations in a database that already contains data.

Use a synchronous URL for async projects

Alembic’s standard runner is synchronous. For an async application, keep DATABASE_URL as postgresql+asyncpg://... for the app, but provide Alembic with a synchronous URL, commonly postgresql+psycopg2://... pointing to the same database. Removing +asyncpg from a URL is not enough unless the corresponding synchronous driver is installed and SQLAlchemy resolves the resulting scheme as intended. Explicitly configure the migration URL and test it separately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start and exercise the API

With the virtual environment active and the database migrated, start Uvicorn from the directory containing your package:

uvicorn your_package.main:app --reload

The --reload option is for development; it watches files and restarts the process. Do not use it as a production process manager. Open /docs in the running application, create an article, and then request the collection endpoint. A successful insert should return a generated integer ID and the row should be visible through a subsequent GET.

SQLModel as an alternative model layer

If you prefer one class to serve as both a database model and a validated API model, SQLModel is the approach used in FastAPI’s official SQL tutorial. It is built on SQLAlchemy and Pydantic and can target PostgreSQL through SQLAlchemy’s dialect support. SQLModel does not remove the need to choose a PostgreSQL driver, manage sessions, protect credentials or run migrations. For larger systems, separate SQLAlchemy and Pydantic schemas can make read/write differences, relationships and security boundaries more explicit.

Common failures and precise fixes

Symptom Likely cause What to check
connection refused PostgreSQL is stopped, listening on another address or blocked by a firewall. Run systemctl status postgresql, verify the host and port, and inspect PostgreSQL’s listening configuration.
password authentication failed Wrong password, role or authentication rule. Try psql with the same URL, confirm the role exists, and reset the password as the PostgreSQL administrator if necessary.
database does not exist The database name in DATABASE_URL differs from the one created with CREATE DATABASE. List databases with sudo -u postgres psql -l and correct the URL.
ModuleNotFoundError: psycopg2 The synchronous driver is not installed in the active virtual environment. Activate .venv and install psycopg2-binary, or use the driver that matches your URL.
postgresql+asyncpg cannot load asyncpg is missing or a synchronous engine is being used with an async URL. Install asyncpg and use create_async_engine with AsyncSession.
Alembic says no changes detected Models were not imported, or target_metadata points to the wrong base. Import every model module in env.py and verify that it uses the same Base as the models.
Tables are missing after a successful app start The application started but migrations were never applied. Run alembic upgrade head against the same database URL the app uses.
Async requests hang or block Synchronous database calls are running inside async routes. Use async SQLAlchemy APIs throughout, or change the route and dependency to the synchronous stack.
current transaction is aborted A statement failed and the session remains in a failed transaction. Call rollback(), fix the original constraint or SQL error, and retry in a new transaction.

Production checklist for an Ubuntu deployment

  • Use a dedicated application role; reserve the postgres administrator for maintenance.
  • Store DATABASE_URL in a secret manager or protected service configuration, not in Git.
  • Require TLS when the database is not on the same trusted host and restrict network access to the application’s addresses.
  • Run Alembic migrations as an explicit deployment step and review generated SQL, especially for renames and data deletion.
  • Set a deliberate connection-pool size that fits PostgreSQL’s connection limit and the number of application workers.
  • Use health checks that distinguish an application process being alive from a database being reachable.
  • Back up PostgreSQL, test restoring those backups, and monitor disk space, connections and slow queries.
  • Run Uvicorn behind a production process manager and reverse proxy rather than using --reload.
  • Pin Python dependencies and record the Ubuntu and PostgreSQL major versions so upgrades are reproducible.

Recommended implementation path

  1. Install and verify PostgreSQL on Ubuntu; use PGDG only when Ubuntu’s packaged major version is not suitable.
  2. Create a separate database and login role with a strong password.
  3. Create a virtual environment and install FastAPI, Uvicorn, SQLAlchemy, Alembic and exactly one PostgreSQL driver for your chosen style.
  4. Put the URL in an environment variable and build the engine and session dependency.
  5. Define SQLAlchemy models and Pydantic request/response schemas, or adopt SQLModel if its combined model style fits the project.
  6. Initialize Alembic, connect target_metadata to your model base, review an autogenerated revision and run alembic upgrade head.
  7. Start Uvicorn, exercise a write and read endpoint, and verify the row directly with psql.
  8. Before deployment, add secret management, backups, TLS, connection limits and a migration gate to your release process.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

AlembicdatabasesFastAPIPostgreSQLPythonSQLAlchemyUbuntu

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.