FastAPI vs Flask 2026: nên chọn framework Python nào
FastAPI vượt trội về async throughput, auto-docs và type safety. Flask giữ vững với codebase legacy ổn định. Benchmark FastAPI 0.136.1 và Flask 3.1.3.
Bởi Ethan
1.936 từ · 10 phút đọc
FastAPI là lựa chọn đúng nếu bạn đang xây dựng async Python API mới trong năm 2026. Tiếp tục dùng Flask nếu bạn đang bảo trì codebase ổn định với nhiều Flask extension. Với hầu hết team, quyết định này thường không khó — phần phức tạp nằm ở các trường hợp ngoại lệ.
Bài viết này dành cho ai
Các Flask developer đang cân nhắc liệu migration có đáng không, và backend developer đang bắt đầu Python API mới trong 2026 và muốn một so sánh thẳng thắn trước khi chọn framework. Nếu bạn không làm việc với Python API, hãy dừng lại ở đây.
Những gì chúng tôi đã kiểm tra
- FastAPI 0.136.1 (phát hành 2026-04-23; yêu cầu Pydantic ≥2.9.0)
- Flask 3.1.3 (phát hành 2026-02-18)
- Server: FastAPI + Uvicorn 0.34.x so với Flask + Gunicorn 23.x (4 workers)
- Công cụ benchmark: wrk, 10 kết nối concurrent, thời gian 30s
- Workload: JSON POST với Pydantic/manual validation, đọc PostgreSQL qua asyncpg (FastAPI) và psycopg2 (Flask)
- Máy chủ: EC2 t3.medium (2 vCPU, 4 GB RAM), Ubuntu 22.04, PostgreSQL 16 chạy local
Tất cả số liệu dưới đây từ các lần chạy của toolchew. TechEmpower Round 22 (tháng 11 năm 2023) được trích dẫn để so sánh giữa các framework. Nếu bạn chưa chọn database, hướng dẫn Postgres vs MySQL 2026 của chúng tôi đề cập tiêu chí lựa chọn cùng bối cảnh managed-cloud.
FastAPI vs Flask: kết quả benchmark
Async: không phải hòa
Flask 3.x đã thêm async views, trông có vẻ như khoảng cách async đã được thu hẹp. Thực ra không phải vậy.
Flask là WSGI. Khi bạn định nghĩa async def trong Flask view, Flask chạy nó trong một thread pool — mỗi request vẫn chặn một Gunicorn worker khi chờ I/O. Bạn không thể await non-blocking database calls từ trong Flask view vì contract WSGI bên dưới không hỗ trợ điều đó. Background tasks cũng không thể chạy bên trong Flask async views.
FastAPI là ASGI-first. Một Uvicorn worker xử lý nhiều request đồng thời qua event loop của Python. Khi await một database call, worker được giải phóng để xử lý request khác thay vì block một thread. Đây không phải chênh lệch lý thuyết; nó thể hiện rõ ở throughput khi endpoint chờ I/O.
Benchmark xác nhận điều này: với PostgreSQL workload và 10 kết nối concurrent, FastAPI + asyncpg + orjson đạt 1,885 req/s. Flask + Gunicorn với 4 workers đạt 1,478 req/s — khoảng cách 28% nghiêng về FastAPI. Scale lên 100 hoặc 1,000 kết nối concurrent thì khoảng cách càng tăng, vì thêm Gunicorn workers không giải quyết được vấn đề WSGI blocking.
Một lưu ý: endpoint CPU-bound (resize ảnh, tạo PDF, tính toán nặng) không được lợi từ async. Nếu endpoint của bạn không bao giờ chờ I/O, mô hình async của FastAPI không giúp ích gì và sự đơn giản của Flask có thể thắng nhờ tính quen thuộc trong vận hành.
TechEmpower Round 22 xếp FastAPI ngay dưới Starlette/Uvicorn thuần trong số các Python framework — nghĩa là overhead của FastAPI so với ASGI layer riêng của nó là rất nhỏ. Flask không xuất hiện trong nhóm top Python cho JSON serialization.
Developer experience: type hints thay đổi mọi thứ
Flask được thiết kế trước khi type hints tồn tại trong Python. Điều đó vẫn còn thể hiện.
Một Flask endpoint điển hình đọc request body và trả về JSON response:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/items", methods=["POST"])
def create_item():
data = request.get_json()
name = data.get("name") # str? None? không rõ lúc runtime
price = data.get("price") # float? int? None?
if not name or price is None:
return jsonify({"error": "missing fields"}), 400
return jsonify({"name": name, "price": price})
Endpoint tương tự trong FastAPI:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items")
async def create_item(item: Item) -> Item:
return item
FastAPI validate request body theo Item trước khi function của bạn chạy. Nếu client gửi price: "free", FastAPI trả về 422 có cấu trúc với field và error type cụ thể — trước khi bạn đụng vào một dòng logic ứng dụng. Tương đương trong Flask là một KeyError hoặc TypeError trên production.
Thông tin type lan truyền đến editor. FastAPI endpoint với Pydantic v2 trong chain cho bạn autocomplete trên item.name, bắt lỗi đánh máy khi viết code, và giúp refactor có thể kiểm tra được. Flask với request.get_json() trả về Any — editor không thể giúp gì bạn.
FastAPI 0.100.0 đã thêm hỗ trợ Pydantic v2 song song với v1. FastAPI hiện tại (0.136.1) yêu cầu Pydantic ≥2.9.0; Pydantic v1 không còn được hỗ trợ. Nếu dự án Flask của bạn dùng Pydantic v1, migrate sang FastAPI đồng nghĩa phải nâng cấp Pydantic v2 cùng lúc. Đây không phải lúc nào cũng nhỏ.
OpenAPI docs: không cần cấu hình vs phải tự dựng
FastAPI tự sinh /docs (Swagger UI) và /redoc (ReDoc) từ route signature và Pydantic model mà không cần cấu hình gì. Thêm endpoint, refresh /docs, endpoint đó được document ngay với request/response schema và panel “Try it out” live.
Flask không có tính năng sinh docs tích hợp. Các lựa chọn bên thứ ba:
- flask-smorest: được bảo trì tích cực, gần giống model FastAPI nhất nhưng yêu cầu marshmallow schema tường minh thay vì Pydantic
- flasgger: cũ hơn, dựa trên YAML docstrings, bảo trì không đồng đều
- apiflask: bọc Flask với interface kiểu FastAPI; thêm sinh docs nhưng về bản chất là một framework riêng
Với internal tool có một hoặc hai endpoint, sự khác biệt này không đáng kể. Với team làm public API hoặc service mà frontend developer phụ thuộc vào spec cập nhật, docs tự sinh từ chính code validate request là khoản tiết kiệm thời gian thực sự.
Hệ sinh thái: extensions của Flask trưởng thành, FastAPI đang lớn lên
Flask có một thập kỷ extension từ bên thứ ba. Nếu stack của bạn có Flask-SQLAlchemy, Flask-Login, Flask-Migrate, Flask-Admin, hay Flask-Caching, đó là những công cụ đã được kiểm chứng trong production. Được bảo trì tốt, có tài liệu đầy đủ, và bao gồm cả các edge case từ nhiều năm thực tế.
Các tương đương của FastAPI:
| Nhu cầu | Flask | FastAPI |
|---|---|---|
| ORM | Flask-SQLAlchemy | SQLAlchemy (trực tiếp) hoặc SQLModel |
| Auth | Flask-Login | fastapi-users, python-jose |
| Migrations | Flask-Migrate (Alembic) | Alembic (trực tiếp) |
| Admin panel | Flask-Admin | fastapi-admin, CRUDAdmin (kém trưởng thành hơn) |
| Rate limiting | Flask-Limiter | slowapi |
| Background tasks | Celery + Flask integration | Celery, hoặc built-in BackgroundTasks cho dùng nhẹ |
FastAPI làm việc trực tiếp với SQLAlchemy mà không cần Flask wrapper. SQLModel (từ tác giả FastAPI) bổ sung Pydantic lên trên SQLAlchemy — bạn định nghĩa một model class duy nhất xử lý cả ORM lẫn API validation. Đây là bước cải thiện DX thực sự. Đánh đổi là SQLModel còn trẻ và SQLAlchemy-direct có nhiều góc khuất hơn với người mới bắt đầu.
Admin panel là nơi Flask vẫn thắng. Flask-Admin tự sinh CRUD views cho SQLAlchemy model. FastAPI chưa có gì tương đương dùng được ngay.
Nếu admin, ORM tích hợp và hệ thống auth của Django là yếu tố bạn đang cân nhắc, hãy xem Django vs FastAPI 2026 — bài đó phân tích quyết định tương tự qua góc nhìn Django.
Lộ trình migrate: những thứ thực sự thay đổi
Chuyển một Flask Blueprint sang FastAPI APIRouter cần ba thay đổi cụ thể:
1. Blueprint → APIRouter
# Flask
from flask import Blueprint
bp = Blueprint("items", __name__, url_prefix="/items")
# FastAPI
from fastapi import APIRouter
router = APIRouter(prefix="/items", tags=["items"])
2. Route decorators
# Flask
@bp.route("/<int:item_id>", methods=["GET"])
def get_item(item_id: int):
...
# FastAPI
@router.get("/{item_id}")
async def get_item(item_id: int):
...
3. Dependency injection: @decorator → Depends()
Flask dùng before_request decorators và g cho per-request state (auth, DB sessions). FastAPI dùng Depends():
# FastAPI — DB session dạng dependency
from fastapi import Depends
from sqlalchemy.orm import Session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@router.get("/{item_id}")
async def get_item(item_id: int, db: Session = Depends(get_db)):
return db.query(Item).get(item_id)
Depends() tường minh, có thể test, và có thể kết hợp theo những cách mà g của Flask không làm được. Auth middleware, DB sessions, rate limits — đều injectable, đều có thể override trong test mà không cần monkeypatch.
Migration có tính cơ học với các endpoint đơn giản. Phần khó là:
- Chuyển logic auth
before_requestsang FastAPI middleware hoặcDepends() - Re-test các Flask extension phụ thuộc vào request context internals
- Nâng cấp lên Pydantic v2 nếu bạn đang dùng v1
Với service 20–30 endpoints và không phụ thuộc nhiều vào Flask extension, dự kiến 2–4 ngày công để migrate và re-test.
Kết luận
| Chọn FastAPI khi… | Tiếp tục dùng Flask khi… |
|---|---|
| Bạn bắt đầu Python API mới trong 2026 | Bạn có Flask codebase ổn định với nhiều extension |
| Endpoint của bạn I/O-bound (DB, HTTP calls) | Workload của bạn CPU-bound và async không mang lại lợi ích |
| Team dùng type hints xuyên suốt | Team chưa quen với async Python |
| Bạn cần OpenAPI docs tự sinh | Bạn cần Flask-Admin hoặc admin panel trưởng thành |
| Bạn đang tích hợp với hệ sinh thái ML/data | Bạn có lịch sử migration Flask-SQLAlchemy không muốn đụng vào |
FastAPI đạt 470 triệu lượt tải PyPI mỗi tháng so với 203 triệu của Flask (tháng 5 năm 2026) — con số này phản ánh hướng đi của các dự án mới. Lượt tải của Flask bao gồm indirect dependencies (được bundle trong nhiều toolchain), nhưng xu hướng rõ ràng. FastAPI là lựa chọn mặc định cho Python API mới.
Nếu bạn muốn học có cấu trúc để thực hiện migration, FastAPI - The Complete Course trên Udemy bao gồm async patterns, Pydantic v2, và dependency injection với các dự án thực hành. Đáng học nếu bạn đang đưa một team mới làm quen với async Python.
Lưu ý
Quart là lựa chọn trung gian mà chúng tôi chưa benchmark: đây là Flask API trên ASGI, cho phép bạn giữ sự quen thuộc với Flask extension trong khi có được hỗ trợ async thực sự. Đáng đánh giá nếu chi phí migration là rào cản chính và bộ Flask extension hiện tại không thể thay thế.
Phương pháp benchmark: Số liệu trên từ các lần chạy wrk của toolchew với 10 kết nối concurrent trên PostgreSQL workload (EC2 t3.medium, PostgreSQL 16). Concurrency trên production thường cao hơn; ở 100+ kết nối concurrent, khoảng cách async nghiêng về FastAPI thường tăng thêm. Hãy benchmark workload thực tế của bạn trước khi quyết định.
Lưu ý về TechEmpower: Round 22 từ tháng 11 năm 2023. Phiên bản framework đã thay đổi; hãy dùng những con số đó như hướng chỉ đường, không phải số liệu chính xác.
Xung đột lợi ích: Bài viết này có một affiliate link (Udemy course). Kết quả benchmark và khuyến nghị về framework độc lập với trạng thái affiliate.