How to Connect to PostgreSQL with FastAPI: Simple Guide
To connect
FastAPI to PostgreSQL, use an async database library like SQLAlchemy with asyncpg driver or the databases package. Define your database URL, create an async engine, and use dependency injection to access the database in your routes.Syntax
This is the basic pattern to connect FastAPI to PostgreSQL using async SQLAlchemy and the asyncpg driver:
DATABASE_URL: Your PostgreSQL connection string.create_async_engine: Creates an async engine for database communication.AsyncSession: Manages async database sessions.Depends: Injects the session into FastAPI routes.
python
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from fastapi import FastAPI, Depends DATABASE_URL = "postgresql+asyncpg://user:password@localhost/dbname" engine = create_async_engine(DATABASE_URL, echo=True) async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) async def get_session() -> AsyncSession: async with async_session() as session: yield session app = FastAPI()
Example
This example shows a complete FastAPI app connecting to PostgreSQL, creating a simple table, and querying data asynchronously.
python
from fastapi import FastAPI, Depends from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker, declarative_base from sqlalchemy import Column, Integer, String, select DATABASE_URL = "postgresql+asyncpg://user:password@localhost/dbname" engine = create_async_engine(DATABASE_URL, echo=True) async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) Base = declarative_base() class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) name = Column(String, index=True) async def get_session() -> AsyncSession: async with async_session() as session: yield session app = FastAPI() @app.on_event("startup") async def startup(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) @app.post("/users/") async def create_user(name: str, session: AsyncSession = Depends(get_session)): user = User(name=name) session.add(user) await session.commit() await session.refresh(user) return {"id": user.id, "name": user.name} @app.get("/users/") async def read_users(session: AsyncSession = Depends(get_session)): result = await session.execute(select(User)) users = result.scalars().all() return users
Output
When running, the app connects to PostgreSQL, creates the users table, and supports POST /users/ to add users and GET /users/ to list them.
Common Pitfalls
Common mistakes when connecting FastAPI to PostgreSQL include:
- Using synchronous database drivers instead of async ones, causing blocking.
- Not using
async_sessionandAsyncSessionfor async operations. - Forgetting to create tables before querying, leading to errors.
- Hardcoding credentials without environment variables, risking security.
python
## Wrong: Using synchronous engine in async FastAPI from sqlalchemy import create_engine engine = create_engine("postgresql://user:password@localhost/dbname") # sync engine ## Right: Use async engine with asyncpg from sqlalchemy.ext.asyncio import create_async_engine engine = create_async_engine("postgresql+asyncpg://user:password@localhost/dbname")
Quick Reference
Tips for connecting FastAPI to PostgreSQL:
- Use
postgresql+asyncpgin your database URL for async support. - Use
AsyncSessionandasync_sessionfor database sessions. - Run
Base.metadata.create_allon startup to create tables. - Use dependency injection with
Dependsto get sessions in routes. - Keep credentials secure using environment variables or secrets management.
Key Takeaways
Use async SQLAlchemy with the asyncpg driver for non-blocking PostgreSQL access in FastAPI.
Create an async engine and sessionmaker, then inject sessions into routes with Depends.
Always create your database tables on app startup to avoid runtime errors.
Avoid synchronous database drivers to prevent blocking FastAPI's async event loop.
Secure your database credentials and avoid hardcoding them in your code.