작년 10월, 팀에서 새 ML 추론 서비스를 짜야 하는 상황이 왔다. 4명짜리 팀, 타이트한 일정, 그리고 “어떤 프레임워크 쓸 거야?”라는 질문. 나는 Django로 3년, Flask로 1년을 써봤고 FastAPI는 사이드 프로젝트에서만 건드려봤던 상황이었다.
결국 2주를 써서 세 가지를 모두 제대로 테스트해봤다. 이 글은 그 결과다.
FastAPI가 정말 AI 백엔드에 맞는지 직접 확인해봤다
FastAPI 0.115.x 기준으로 작업했다. 첫인상은 솔직히 좋았다. Python 타입 힌트 기반으로 OpenAPI 문서가 자동으로 생성되고, async/await이 기본이며, Pydantic v2를 통한 데이터 검증이 깔끔하다.
우리 팀이 만든 건 LLM 추론 엔드포인트였다. 요청이 들어오면 모델을 호출하고 스트리밍으로 응답을 반환하는 구조. FastAPI의 StreamingResponse가 여기서 진짜 빛났다.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
import asyncio
app = FastAPI()
class InferenceRequest(BaseModel):
prompt: str
max_tokens: int = 512
temperature: float = 0.7
async def stream_tokens(prompt: str, max_tokens: int):
# 실제로는 여기서 모델 호출 — 지연 시뮬레이션
for i in range(max_tokens):
yield f"data: token_{i}\n\n"
await asyncio.sleep(0.01)
@app.post("/infer")
async def infer(req: InferenceRequest):
# 타입 검증은 Pydantic이, 문서화는 FastAPI가 알아서 해줌
return StreamingResponse(
stream_tokens(req.prompt, req.max_tokens),
media_type="text/event-stream"
)
같은 걸 Flask에서 구현하면 훨씬 장황해진다. 타입 검증을 위해 marshmallow나 pydantic을 별도로 붙여야 하고, 스트리밍도 Response 객체를 직접 다뤄야 한다. 코드 줄 수 문제가 아니라, 그냥 생각해야 할 것들이 많아진다는 게 피로하다.
그런데 FastAPI를 쓰면서 예상 못 한 문제가 하나 있었다. 의존성 주입(Dependency Injection) 시스템이 처음엔 직관적인 것 같은데, 중첩이 깊어지면 — 특히 DB 세션, 인증, rate limiter를 같이 쓸 때 — 디버깅이 꽤 까다로워진다. Depends() 체인이 어디서 실패했는지 스택 트레이스만 보고 파악하기 어려울 때가 있다. Starlette 기반 미들웨어 순서도 Django에 익숙하면 초반에 좀 헷갈린다.
API 서버, 특히 ML/AI 추론 서버에는 FastAPI가 현재 가장 합리적인 선택이다. 타입 안전성, async 지원, 자동 문서화가 한 패키지로 온다. 이 세 가지를 다른 방법으로 조합하려고 하면 코드보다 설정을 쓰는 시간이 더 길어진다.
Django: “낡은” 프레임워크라고 치부하기엔 이르다
솔직히 말하면, 나도 작년까지 Django를 “너무 무거운” 것으로 봤다. 그런데 Django 5.1이 나오면서 생각이 조금 바뀌었다.
우리 회사 메인 서비스는 3년째 Django로 돌아가고 있다. 팀원 7명, 복잡한 권한 시스템, 어드민 패널, 수십 개의 ORM 쿼리들. 이 맥락에서 Django는 여전히 강하다.
# Django ORM — 관계형 데이터 처리가 이렇게 간결함
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
published_at = models.DateTimeField(auto_now_add=True)
# N+1 없이 한 번에 — FastAPI+SQLAlchemy로 하면 설정이 두 배는 됨
posts = Post.objects.select_related('author').filter(
published_at__year=2026
).order_by('-published_at')[:20]
select_related, prefetch_related를 제대로 쓸 줄 알면 N+1 쿼리 문제를 코드 레벨에서 꽤 깔끔하게 잡을 수 있다. FastAPI에서 SQLAlchemy async를 쓰면 가능은 하지만, 보일러플레이트가 상당하다.
Django REST Framework(DRF)는 아직도 많이 쓰이는데, 솔직히 serializer 코드가 중복되는 느낌이 든다. 그래서 요즘은 django-ninja를 Django 위에 얹어 쓰는 팀들이 늘고 있다. FastAPI처럼 Pydantic 기반 스키마를 쓸 수 있어서 DRF보다 훨씬 덜 장황하다. 이 조합이 꽤 쓸 만하다.
Django의 진짜 강점은 “배터리 포함”이라는 점이다. 인증, 어드민, 마이그레이션, 세션 관리가 모두 기본 탑재다. 스타트업 초기에 빠르게 프로덕트를 내야 한다면, 이 생산성은 무시 못한다.
async 지원이 개선됐다고는 하지만 Django 5.x의 async ORM은 아직 완전하지 않다. 일부 기능은 sync_to_async로 감싸야 하고, 이게 코드를 복잡하게 만든다. FastAPI + SQLAlchemy async 스택과 비교하면 격차가 있다.
내 경험상 Django가 맞는 케이스: 팀이 3명 이상이고, 복잡한 도메인 로직이 있고, 어드민이 필요하며, 빠르게 MVP를 만들어야 할 때. 반대로 순수 API 서버에서 Django를 쓰는 건 좀 과하다.
Flask: 2026년에도 쓸 이유가 있나?
있다. 다만, 좁다.
Flask를 마지막으로 진지하게 쓴 게 2024년 초였다. 사내 소규모 데이터 파이프라인 모니터링 도구를 만들었는데 — 엔드포인트 5개, 인증 없음, 빠른 프로토타입 — 그 정도 범위에선 Flask가 딱 맞았다. 필요한 것만 있고 나머지는 없었다.
문제는 그 “필요한 것만”이라는 경계가 굉장히 빠르게 바뀐다는 거다. 타입 검증이 필요해지면 marshmallow 붙이고, 문서화가 필요하면 flasgger 붙이고, async가 필요해지면… 그냥 다른 프레임워크를 써야 한다는 결론에 도달한다.
Flask 3.0이 나오면서 async 지원이 개선됐지만 FastAPI와 비교하면 async가 여전히 일급 시민(first-class citizen)이 아니다. quart(Flask와 호환되는 async 버전)로 갈아타는 것도 고려해봤는데, 그럴 바엔 FastAPI를 쓰는 게 낫다. 라이브러리를 바꾸는데 프레임워크를 바꾸는 수준의 공수가 든다면 그냥 프레임워크를 바꾸는 게 맞다.
Flask가 말이 되는 케이스: 기존 Flask 코드베이스를 유지보수할 때. 또는 팀이 Flask에 매우 익숙하고 프로젝트 복잡도가 낮을 때. 새 그린필드 프로젝트에서는 — 내가 팀 리드라면 Flask를 고르지 않을 것 같다.
내가 가장 크게 틀렸던 것: 성능보다 팀 컨텍스트가 더 중요하다
처음에 나는 벤치마크부터 봤다. FastAPI는 uvicorn 위에서 돌아가고 Django보다 처리량이 높다는 건 사실이다. 단순 엔드포인트 기준으로 FastAPI가 Django DRF보다 2-3배 빠른 경우도 있다.
그런데 실무에서 병목은 대부분 프레임워크 자체가 아니라 DB 쿼리, 외부 API 호출, 캐싱 전략에 있다. FastAPI로 바꿔도 느린 쿼리는 여전히 느리다. 이걸 뒤늦게 깨달았다.
더 중요한 건 팀이다. 여기서 내가 직접 겪은 실수를 하나 고백하면 — 2024년 초에 팀 프로젝트를 Django에서 FastAPI로 마이그레이션하면서 “2주면 되겠지”라고 했다. 결과적으로 안정화까지 6주가 걸렸다. Pydantic v2의 변경사항, async 패턴, SQLAlchemy 2.0 스타일이 합쳐지면 꽤 큰 인지 부하다. 기술적인 이전보다 팀이 async 패턴에 익숙해지는 게 더 오래 걸렸다. 그리고 그 마이그레이션을 금요일 오후에 배포하기” rel=”nofollow sponsored” target=”_blank”>배포하기” rel=”nofollow sponsored” target=”_blank”>배포하기” rel=”nofollow sponsored” target=”_blank”>배포하기 시작했는데 — 다들 알다시피 그건 좋은 생각이 아니었다.
어떤 프레임워크를 선택하든, 팀의 현재 스킬셋과 프로젝트의 실제 요구사항을 먼저 정직하게 평가하는 게 벤치마크보다 중요하다. 팀 규모가 10명을 넘어가고 비즈니스 로직이 복잡해지면 Django의 체계성이 FastAPI의 유연성보다 더 중요해진다. 유연성은 양날의 검이라서, 팀마다 아키텍처가 달라지는 문제가 생기기도 한다.
그래서 뭘 써야 하나 — 내 결론
“상황에 따라 다르다”는 답을 싫어한다. 그래서 직접적으로 말하겠다.
API 서버, ML/AI 서비스: FastAPI. 망설일 이유 없다. Pydantic v2, async, 자동 OpenAPI 문서화. 팀이 async에 익숙하다면 생산성도 높다.
풀스택 웹앱, 복잡한 도메인 로직: Django. 특히 어드민이 필요하거나 빠르게 MVP를 쳐야 한다면. django-ninja를 같이 쓰면 DRF보다 훨씬 쾌적하다.
Flask: 기존 코드베이스 유지보수 외에는 새 프로젝트에 추천하기 어렵다.
지금 내 사이드 프로젝트는 FastAPI + SQLAlchemy 2.0 async + PostgreSQL 스택이다. AI 관련 서비스를 실험하기에 이 스택이 가장 편하다.
Anyway — 가장 좋은 프레임워크는 네가 팀과 함께 제대로 쓸 수 있는 것이다. 6주짜리 마이그레이션을 직접 겪고 나서야 진심으로 공감하게 됐다.