Framework choices feel momentous when you’re making them. In hindsight, they’re rarely catastrophic either way — but they do shape your codebase’s character for years.
We chose FastAPI over Django for Fintropy’s backend. 18 months and 84 endpoints later, I want to give an honest account of that decision: what worked, what we missed, and how we’d think about it if we were starting today.
The Decision Context
We were building a FinOps API that would:
- Scan cloud accounts across AWS, Azure, and GCP
- Process billing data and detect cost anomalies
- Handle SLA breach detection and credit claim filing
- Serve a React frontend with real-time updates
The backend is heavily I/O-bound. Every scan job fires off hundreds of API calls to cloud providers, waits for responses, processes data, stores results. The bottleneck is network latency, not CPU.
That context mattered a lot for the decision.
Why FastAPI Won
1. Async-first matters for I/O-bound workloads
FastAPI is built on Starlette and Uvicorn, which are async-native. When you’re making hundreds of concurrent API calls to AWS, Azure, and GCP, async lets you fire them in parallel without blocking:
async def scan_all_providers(subscription: CloudSubscription):
results = await asyncio.gather(
scan_aws(subscription),
scan_azure(subscription),
scan_gcp(subscription),
)
return results
Django can do async, but it feels bolted on. The ORM wasn’t designed for it. You end up with sync_to_async wrappers everywhere, which negates much of the benefit.
2. Dependency injection made auth clean
FastAPI’s dependency system let us compose authentication, tenant isolation, and license checks into reusable units:
@router.get("/api/subscriptions")
async def list_subscriptions(
db: Session = Depends(set_tenant_context),
current_user: User = Depends(get_current_user),
_: None = Depends(verify_license_active),
):
...
That Depends() chain handles JWT validation, tenant session setup, and feature gating in a single line declaration. Any endpoint that omits one of these dependencies simply doesn’t have that protection — which is explicit and auditable.
3. Pydantic validation at the boundary
Request validation is automatic and generates clear error responses. More importantly, it forced us to define our data contracts explicitly — which became invaluable when we started building the frontend and needed a stable API contract.
4. Auto-generated OpenAPI documentation
We didn’t value this until we needed it. When our first enterprise customer’s IT team asked for API documentation to review before onboarding, we sent them the Swagger URL. It was up to date. It was accurate. It was free.
What We Missed
Django Admin
This is the big one. We undervalued Django Admin’s internal tooling value completely.
In our first six months, we built a custom internal admin panel for Fintropy: user management, tenant management, scan job monitoring, license management. That took three engineers roughly four weeks of effort.
Django Admin would have given us 80% of that for free, with a week of customisation.
We’ve made our peace with this. The custom panel has capabilities Django Admin couldn’t easily support — multi-cloud subscription management, real-time scan monitoring, SLA breach workflows. But we paid a real cost to get there.
SQLAlchemy vs Django ORM
Django’s ORM is more mature for complex queries. SQLAlchemy — the standard FastAPI/Python choice — gives you more power (Core + ORM modes, fine-grained control over SQL generation) but requires more discipline.
We’ve written some very elegant SQLAlchemy queries. We’ve also written some that are hard to read and harder to debug. Django ORM has guardrails that prevent some of the worst patterns.
What We’d Do the Same
Everything on the async side. If your backend is primarily I/O-bound — which most modern cloud-facing backends are — FastAPI’s async foundation is genuinely better.
The dependency injection system is something we’d miss immediately if we moved to Django REST Framework. It’s clean, composable, and makes security properties of each endpoint explicit.
How We’d Think About It Today
Choose FastAPI if:
- Your backend is heavily I/O-bound (API aggregation, data pipeline, cloud integration)
- You want strong async primitives without workarounds
- You’re building an API-first product with an explicit contract to maintain
- Your team is comfortable writing more boilerplate for internal tooling
Choose Django if:
- You need a content management layer, admin panel, or backoffice quickly
- Your team has strong Django experience
- Your workload is CPU-bound or not latency-sensitive
- You want the ecosystem — auth libraries, payment integrations, etc.
The right framework isn’t the fastest or the most popular. It’s the one whose constraints match your problem for the next 18 months.
Fintropy is a multi-cloud FinOps platform in private beta. Learn more at nuvikatech.com