How a Simple Depends() Fix Halved My FastAPI Response Times
After noticing API endpoints taking up to a second, the author discovered that misusing FastAPI's Depends() with a get_db() function that recreated the database engine on each request caused severe latency, and by refactoring get_db() into a proper generator that reuses a single engine, response times were roughly halved.
I built a FastAPI backend service with several endpoints, some SQL queries and user authentication. Everything seemed to run fine… until I checked performance.
Some endpoints took 800 ms. Others over a second. And this was only with test data. 😬
I know FastAPI is supposed to be fast. The problem wasn’t the framework but my own code, so I started profiling the API, cursing the logs, and trying to optimise the SQL queries.
Eventually I discovered a simple trick—a single change—that cut response times in half.
No extra hardware or complex caching needed, just do the following:
✅ Correct use of Depends()
If you use FastAPI with SQLAlchemy or SQLModel, your DB session setup might look like this:
from fastapi import Depends
from sqlalchemy.orm import Session
from app.db import get_db
@app.get("/items/")
def read_items(db: Session = Depends(get_db)):
return db.query(Item).all()The key is:
Your get_db() function needs to be a generator —and more importantly, you must not create a new engine on every request.
I realized my get_db() function incorrectly created a new engine for each request, which added overhead and caused poor performance.
🛠 Fix: proper get_db() pattern
Here is the correct implementation:
# db/session.py
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()Why this matters:
Engine is created only once, not per request.
Session scope is limited to the request and closed properly.
No connection or thread leaks.
⏱ Before and after fix
After the fix, performance improvements are as follows:
Performance comparison
Response speed doubled!
🔍 Extra tip: use async only when needed
Do not mix synchronous database drivers with async def endpoints unless you know what you're doing.
Using a sync driver (e.g., classic SQLAlchemy) in async def routes makes FastAPI run it in a thread pool, adding extra overhead.
Therefore, either:
Use sync routes with SQLAlchemy.
Or switch to async‑capable drivers such as asyncpg + SQLAlchemy 2.0 or encode/databases, and use fully async async def routes.
For me, changing the endpoint from async def to def also saved a few milliseconds.
🔥 Key takeaways: the trick that made my API fast again
✅ Properly define get_db() — engine created once, sessions provided as needed.
✅ Avoid creating the engine in the request path.
✅ Do not mix synchronous DB drivers with async def routes.
✅ Use httpx, TestClient or Locust for performance analysis.
Now it seems obvious, but I spent days trying to optimise performance until I fixed these fundamental issues.
Sometimes a correctly placed Depends() solves everything.
✅ Final summary
FastAPI is designed for speed, but only if you use it correctly.
So if you’re wondering why your FastAPI app isn’t as fast as expected, first check your dependencies. The bottleneck might be hidden in that seemingly harmless get_db().
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
