[{"data":1,"prerenderedAt":869},["ShallowReactive",2],{"nav":3,"page-\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002F":310,"surround-\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002F":867},[4,96,212],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,30,42,54,66,90],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation and Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators and Field Constraints in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18,24],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Creating Reusable Custom Validators in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Pydantic v2 Async Custom Validator: What to Do Instead","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator\u002Findex",[29],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"JSON Schema Customization in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[35,36],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Customizing OpenAPI Schema Generation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[41],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[47,48],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Handling Deeply Nested JSON Models Efficiently","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Performance Optimization for Pydantic Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[59,60],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Pydantic Model Serialization Performance in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Pydantic V2 Migration Guide for FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[71,72,78,84],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Migrate @validator to @field_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Migrating from Pydantic v1 to v2 Without Breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"model_config vs class Config in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Type Hinting and IDE Integration in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[95],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"Async Background Tasks Observability","\u002Fasync-background-tasks-observability","async-background-tasks-observability",[101,104,122,140,158,176,194],{"title":102,"path":98,"stem":103},"Async, Background Tasks, and Observability in FastAPI","async-background-tasks-observability\u002Findex",{"title":105,"path":106,"stem":107,"children":108},"Async Correctness and Concurrency in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Findex",[109,110,116],{"title":105,"path":106,"stem":107},{"title":111,"path":112,"stem":113,"children":114},"FastAPI async def vs def: Performance and When to Use Each","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex",[115],{"title":111,"path":112,"stem":113},{"title":117,"path":118,"stem":119,"children":120},"Fixing Blocking Calls in Async FastAPI Routes","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002Findex",[121],{"title":117,"path":118,"stem":119},{"title":123,"path":124,"stem":125,"children":126},"Async Database Sessions in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions","async-background-tasks-observability\u002Fasync-database-sessions\u002Findex",[127,128,134],{"title":123,"path":124,"stem":125},{"title":129,"path":130,"stem":131,"children":132},"Async SQLAlchemy Session per Request in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request","async-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request\u002Findex",[133],{"title":129,"path":130,"stem":131},{"title":135,"path":136,"stem":137,"children":138},"Fixing asyncpg Connection Pool Exhaustion in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion","async-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion\u002Findex",[139],{"title":135,"path":136,"stem":137},{"title":141,"path":142,"stem":143,"children":144},"Background Task Processing in FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing","async-background-tasks-observability\u002Fbackground-task-processing\u002Findex",[145,146,152],{"title":141,"path":142,"stem":143},{"title":147,"path":148,"stem":149,"children":150},"FastAPI BackgroundTasks vs Celery vs ARQ","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq","async-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq\u002Findex",[151],{"title":147,"path":148,"stem":149},{"title":153,"path":154,"stem":155,"children":156},"Running ARQ Workers with FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi","async-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi\u002Findex",[157],{"title":153,"path":154,"stem":155},{"title":159,"path":160,"stem":161,"children":162},"Caching Strategies in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies","async-background-tasks-observability\u002Fcaching-strategies\u002Findex",[163,164,170],{"title":159,"path":160,"stem":161},{"title":165,"path":166,"stem":167,"children":168},"Cache Invalidation Patterns in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi\u002Findex",[169],{"title":165,"path":166,"stem":167},{"title":171,"path":172,"stem":173,"children":174},"Redis Response Caching in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi\u002Findex",[175],{"title":171,"path":172,"stem":173},{"title":177,"path":178,"stem":179,"children":180},"Observability and Tracing in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing","async-background-tasks-observability\u002Fobservability-and-tracing\u002Findex",[181,182,188],{"title":177,"path":178,"stem":179},{"title":183,"path":184,"stem":185,"children":186},"Instrumenting FastAPI with OpenTelemetry","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry","async-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex",[187],{"title":183,"path":184,"stem":185},{"title":189,"path":190,"stem":191,"children":192},"Structured JSON Logging with Request IDs in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002Findex",[193],{"title":189,"path":190,"stem":191},{"title":195,"path":196,"stem":197,"children":198},"Rate Limiting and Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Findex",[199,200,206],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"FastAPI Rate Limiting with Redis and SlowAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi","async-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi\u002Findex",[205],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"Per-User Token Bucket Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[217,220,232,250,268,280,292],{"title":218,"path":214,"stem":219},"FastAPI Core Architecture and Routing Patterns","core-architecture-routing-patterns\u002Findex",{"title":221,"path":222,"stem":223,"children":224},"Application Factory Patterns in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[225,226],{"title":221,"path":222,"stem":223},{"title":227,"path":228,"stem":229,"children":230},"FastAPI App Factory Pattern for Testing and Deployment","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[231],{"title":227,"path":228,"stem":229},{"title":233,"path":234,"stem":235,"children":236},"Configuration Management in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[237,238,244],{"title":233,"path":234,"stem":235},{"title":239,"path":240,"stem":241,"children":242},"Managing Environment Variables with Pydantic Settings","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[243],{"title":239,"path":240,"stem":241},{"title":245,"path":246,"stem":247,"children":248},"Pydantic Settings vs Dynaconf vs python-decouple","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002Findex",[249],{"title":245,"path":246,"stem":247},{"title":251,"path":252,"stem":253,"children":254},"Dependency Injection Strategies in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[255,256,262],{"title":251,"path":252,"stem":253},{"title":257,"path":258,"stem":259,"children":260},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[261],{"title":257,"path":258,"stem":259},{"title":263,"path":264,"stem":265,"children":266},"Fixing FastAPI Dependency Injection Circular Imports","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix\u002Findex",[267],{"title":263,"path":264,"stem":265},{"title":269,"path":270,"stem":271,"children":272},"Error Handling and Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[273,274],{"title":269,"path":270,"stem":271},{"title":275,"path":276,"stem":277,"children":278},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[279],{"title":275,"path":276,"stem":277},{"title":281,"path":282,"stem":283,"children":284},"Middleware Implementation in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[285,286],{"title":281,"path":282,"stem":283},{"title":287,"path":288,"stem":289,"children":290},"Implementing Custom Middleware for Request Tracing","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[291],{"title":287,"path":288,"stem":289},{"title":293,"path":294,"stem":295,"children":296},"Modular Router Organization in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[297,298,304],{"title":293,"path":294,"stem":295},{"title":299,"path":300,"stem":301,"children":302},"APIRouter Prefix vs Sub-Application Mounting in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting\u002Findex",[303],{"title":299,"path":300,"stem":301},{"title":305,"path":306,"stem":307,"children":308},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[309],{"title":305,"path":306,"stem":307},{"id":311,"title":111,"body":312,"description":821,"extension":822,"meta":823,"navigation":439,"path":112,"seo":865,"stem":113,"__hash__":866},"content\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex.md",{"type":313,"value":314,"toc":806},"minimark",[315,319,326,362,370,375,381,385,401,405,412,544,550,613,620,696,700,730,734,737,768,774,778,802],[316,317,111],"h1",{"id":318},"fastapi-async-def-vs-def-performance-and-when-to-use-each",[320,321,322],"p",{},[323,324,325],"strong",{},"Key takeaways:",[327,328,329,337,343,349,359],"ul",{},[330,331,332,336],"li",{},[333,334,335],"code",{},"async def"," wins only when the handler awaits async I\u002FO and can yield the loop.",[330,338,339,342],{},[333,340,341],{},"def"," handlers run in a thread pool, so synchronous blocking is safe there.",[330,344,345,346,348],{},"The worst case is blocking code inside ",[333,347,335],{},", which freezes the loop for everyone.",[330,350,351,352,354,355,358],{},"Offload unavoidable blocking calls from ",[333,353,335],{}," with ",[333,356,357],{},"anyio.to_thread.run_sync",".",[330,360,361],{},"Confirm your choice by load testing under concurrency, not with a single request.",[320,363,364,365,358],{},"This guide makes the choice concrete; the underlying model is in ",[366,367,369],"a",{"href":368},"\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002F","Async Correctness and Concurrency",[371,372,374],"h2",{"id":373},"the-problem-this-solves","The Problem This Solves",[320,376,377,378,380],{},"Developers often assume ",[333,379,335],{}," is always faster and convert every route, then call a synchronous database driver inside it and wonder why throughput collapsed. The keyword does not make code asynchronous; awaiting async I\u002FO does. Choosing wrong in either direction costs throughput.",[371,382,384],{"id":383},"prerequisites","Prerequisites",[327,386,387,390],{},[330,388,389],{},"FastAPI on Uvicorn.",[330,391,392,393,396,397,400],{},"A load-testing tool such as ",[333,394,395],{},"hey"," or ",[333,398,399],{},"wrk"," to measure under concurrency.",[371,402,404],{"id":403},"step-by-step-implementation","Step-by-Step Implementation",[406,407,409,410],"h3",{"id":408},"_1-async-io-async-def","1. Async I\u002FO → ",[333,411,335],{},[413,414,419],"pre",{"className":415,"code":416,"language":417,"meta":418,"style":418},"language-python shiki shiki-themes github-light","import httpx\n\n\n@app.get(\"\u002Fprofile\")\nasync def profile() -> dict:\n    # Awaiting async I\u002FO lets the loop serve other requests during the wait.\n    async with httpx.AsyncClient() as client:\n        return (await client.get(\"https:\u002F\u002Fapi.example.com\u002Fme\", timeout=5)).json()\n","python","",[333,420,421,434,441,446,463,485,492,510],{"__ignoreMap":418},[422,423,426,430],"span",{"class":424,"line":425},"line",1,[422,427,429],{"class":428},"sD7c4","import",[422,431,433],{"class":432},"sgsFI"," httpx\n",[422,435,437],{"class":424,"line":436},2,[422,438,440],{"emptyLinePlaceholder":439},true,"\n",[422,442,444],{"class":424,"line":443},3,[422,445,440],{"emptyLinePlaceholder":439},[422,447,449,453,456,460],{"class":424,"line":448},4,[422,450,452],{"class":451},"s7eDp","@app.get",[422,454,455],{"class":432},"(",[422,457,459],{"class":458},"sYBdl","\"\u002Fprofile\"",[422,461,462],{"class":432},")\n",[422,464,466,469,472,475,478,482],{"class":424,"line":465},5,[422,467,468],{"class":428},"async",[422,470,471],{"class":428}," def",[422,473,474],{"class":451}," profile",[422,476,477],{"class":432},"() -> ",[422,479,481],{"class":480},"sYu0t","dict",[422,483,484],{"class":432},":\n",[422,486,488],{"class":424,"line":487},6,[422,489,491],{"class":490},"sAwPA","    # Awaiting async I\u002FO lets the loop serve other requests during the wait.\n",[422,493,495,498,501,504,507],{"class":424,"line":494},7,[422,496,497],{"class":428},"    async",[422,499,500],{"class":428}," with",[422,502,503],{"class":432}," httpx.AsyncClient() ",[422,505,506],{"class":428},"as",[422,508,509],{"class":432}," client:\n",[422,511,513,516,519,522,525,528,531,535,538,541],{"class":424,"line":512},8,[422,514,515],{"class":428},"        return",[422,517,518],{"class":432}," (",[422,520,521],{"class":428},"await",[422,523,524],{"class":432}," client.get(",[422,526,527],{"class":458},"\"https:\u002F\u002Fapi.example.com\u002Fme\"",[422,529,530],{"class":432},", ",[422,532,534],{"class":533},"sqxcx","timeout",[422,536,537],{"class":428},"=",[422,539,540],{"class":480},"5",[422,542,543],{"class":432},")).json()\n",[406,545,547,548],{"id":546},"_2-blocking-work-def","2. Blocking work → ",[333,549,341],{},[413,551,553],{"className":415,"code":552,"language":417,"meta":418,"style":418},"@app.get(\"\u002Flegacy-report\")\ndef legacy_report() -> dict:\n    # A sync driver here is fine: FastAPI runs def handlers in a thread pool.\n    rows = sync_db.query(\"SELECT ...\")\n    return {\"rows\": rows}\n",[333,554,555,566,579,584,599],{"__ignoreMap":418},[422,556,557,559,561,564],{"class":424,"line":425},[422,558,452],{"class":451},[422,560,455],{"class":432},[422,562,563],{"class":458},"\"\u002Flegacy-report\"",[422,565,462],{"class":432},[422,567,568,570,573,575,577],{"class":424,"line":436},[422,569,341],{"class":428},[422,571,572],{"class":451}," legacy_report",[422,574,477],{"class":432},[422,576,481],{"class":480},[422,578,484],{"class":432},[422,580,581],{"class":424,"line":443},[422,582,583],{"class":490},"    # A sync driver here is fine: FastAPI runs def handlers in a thread pool.\n",[422,585,586,589,591,594,597],{"class":424,"line":448},[422,587,588],{"class":432},"    rows ",[422,590,537],{"class":428},[422,592,593],{"class":432}," sync_db.query(",[422,595,596],{"class":458},"\"SELECT ...\"",[422,598,462],{"class":432},[422,600,601,604,607,610],{"class":424,"line":465},[422,602,603],{"class":428},"    return",[422,605,606],{"class":432}," {",[422,608,609],{"class":458},"\"rows\"",[422,611,612],{"class":432},": rows}\n",[406,614,616,617,619],{"id":615},"_3-blocking-inside-async-def-offload","3. Blocking inside ",[333,618,335],{}," → offload",[413,621,623],{"className":415,"code":622,"language":417,"meta":418,"style":418},"import anyio\n\n\n@app.get(\"\u002Fdigest\")\nasync def digest() -> dict:\n    # Must call blocking code from async def → offload so the loop stays free.\n    value = await anyio.to_thread.run_sync(blocking_hash)\n    return {\"digest\": value}\n",[333,624,625,632,636,640,651,666,671,684],{"__ignoreMap":418},[422,626,627,629],{"class":424,"line":425},[422,628,429],{"class":428},[422,630,631],{"class":432}," anyio\n",[422,633,634],{"class":424,"line":436},[422,635,440],{"emptyLinePlaceholder":439},[422,637,638],{"class":424,"line":443},[422,639,440],{"emptyLinePlaceholder":439},[422,641,642,644,646,649],{"class":424,"line":448},[422,643,452],{"class":451},[422,645,455],{"class":432},[422,647,648],{"class":458},"\"\u002Fdigest\"",[422,650,462],{"class":432},[422,652,653,655,657,660,662,664],{"class":424,"line":465},[422,654,468],{"class":428},[422,656,471],{"class":428},[422,658,659],{"class":451}," digest",[422,661,477],{"class":432},[422,663,481],{"class":480},[422,665,484],{"class":432},[422,667,668],{"class":424,"line":487},[422,669,670],{"class":490},"    # Must call blocking code from async def → offload so the loop stays free.\n",[422,672,673,676,678,681],{"class":424,"line":494},[422,674,675],{"class":432},"    value ",[422,677,537],{"class":428},[422,679,680],{"class":428}," await",[422,682,683],{"class":432}," anyio.to_thread.run_sync(blocking_hash)\n",[422,685,686,688,690,693],{"class":424,"line":512},[422,687,603],{"class":428},[422,689,606],{"class":432},[422,691,692],{"class":458},"\"digest\"",[422,694,695],{"class":432},": value}\n",[371,697,699],{"id":698},"edge-cases-and-gotchas","Edge Cases and Gotchas",[327,701,702,711,724],{},[330,703,704,707,708,710],{},[323,705,706],{},"Hidden blocking."," An ",[333,709,335],{}," that calls a library which blocks internally is as harmful as an explicit blocking call; profile it.",[330,712,713,716,717,719,720,358],{},[323,714,715],{},"Thread-pool saturation."," Many slow ",[333,718,341],{}," handlers exhaust the thread pool and reintroduce queuing; move heavy work to a ",[366,721,723],{"href":722},"\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002F","queue",[330,725,726,729],{},[323,727,728],{},"CPU-bound work."," Threads do not help CPU-bound work because of the GIL; use a process pool.",[371,731,733],{"id":732},"verification","Verification",[320,735,736],{},"Load test both styles under concurrency and compare throughput:",[413,738,742],{"className":739,"code":740,"language":741,"meta":418,"style":418},"language-bash shiki shiki-themes github-light","# A correctly async endpoint sustains high concurrency; a blocked one serializes.\nhey -z 10s -c 50 http:\u002F\u002Flocalhost:8000\u002Fprofile\n","bash",[333,743,744,749],{"__ignoreMap":418},[422,745,746],{"class":424,"line":425},[422,747,748],{"class":490},"# A correctly async endpoint sustains high concurrency; a blocked one serializes.\n",[422,750,751,753,756,759,762,765],{"class":424,"line":436},[422,752,395],{"class":451},[422,754,755],{"class":480}," -z",[422,757,758],{"class":458}," 10s",[422,760,761],{"class":480}," -c",[422,763,764],{"class":480}," 50",[422,766,767],{"class":458}," http:\u002F\u002Flocalhost:8000\u002Fprofile\n",[320,769,770,771,773],{},"If latency scales linearly with concurrency on an ",[333,772,335],{}," endpoint, it is blocking the loop somewhere.",[371,775,777],{"id":776},"related-reading","Related Reading",[327,779,780,788],{},[330,781,782,785,786,358],{},[323,783,784],{},"Up to the topic:"," ",[366,787,369],{"href":368},[330,789,790,785,793,797,798,358],{},[323,791,792],{},"Related guides:",[366,794,796],{"href":795},"\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002F","Fixing Blocking Calls in Async Routes"," and ",[366,799,801],{"href":800},"\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002F","Async Database Sessions",[803,804,805],"style",{},"html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":418,"searchDepth":436,"depth":436,"links":807},[808,809,810,818,819,820],{"id":373,"depth":436,"text":374},{"id":383,"depth":436,"text":384},{"id":403,"depth":436,"text":404,"children":811},[812,814,816],{"id":408,"depth":443,"text":813},"1. Async I\u002FO → async def",{"id":546,"depth":443,"text":815},"2. Blocking work → def",{"id":615,"depth":443,"text":817},"3. Blocking inside async def → offload",{"id":698,"depth":436,"text":699},{"id":732,"depth":436,"text":733},{"id":776,"depth":436,"text":777},"Understand FastAPI async def vs def: how each runs, why mixing blocking code into async def hurts throughput, the thread pool for def handlers, and a decision rule with benchmarks.","md",{"slug":824,"type":825,"breadcrumb":826,"datePublished":838,"dateModified":839,"howto":840,"faq":858},"fastapi-async-def-vs-def-performance","long_tail",[827,830,833,835],{"label":828,"path":829},"Home","\u002F",{"label":831,"path":832},"Async, Background Tasks & Observability","\u002Fasync-background-tasks-observability\u002F",{"label":834,"path":368},"Async Correctness & Concurrency",{"label":836,"path":837},"async def vs def Performance","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002F","2026-02-17","2026-06-18",{"name":841,"steps":842},"Choose between async def and def in FastAPI",[843,846,849,852,855],{"name":844,"text":845},"Identify the work type","Determine whether the handler does async I\u002FO, blocking I\u002FO, or CPU-bound work.",{"name":847,"text":848},"Use async def for async I\u002FO","If the handler awaits async clients, declare it async def so it yields the loop.",{"name":850,"text":851},"Use def for blocking work","If the work is synchronous and blocking, declare it def so FastAPI runs it in a thread pool.",{"name":853,"text":854},"Never block inside async def","If you must call blocking code from async def, offload it with anyio.to_thread.run_sync.",{"name":856,"text":857},"Measure under concurrency","Load test with concurrent requests to confirm the loop is not blocked.",[859,862],{"q":860,"a":861},"Is async def always faster than def in FastAPI?","No. async def is faster only when the handler awaits async I\u002FO, because that is when the loop can serve other requests during the wait. For purely synchronous blocking work, def is actually safer because FastAPI runs it in a thread pool, whereas the same blocking code in async def would freeze the loop and reduce throughput.",{"q":863,"a":864},"How many threads does FastAPI use for def handlers?","Starlette runs def handlers in an anyio thread pool with a default capacity that is bounded, not unlimited. Long-running blocking def handlers can saturate it, at which point further requests queue. For heavy blocking workloads, tune the pool size or move the work to a process pool or a background queue.",{"title":111,"description":821},"eCW4M4Ad-HvTd6Ea7fUbHycj2KTBDAjcpTAPdmI7wiM",[868,868],null,1781809863424]