Skip to content

Start here ​

In one sentence

This is a hands-on workshop on five ways a FastAPI service becomes slow in ways that only show up under real concurrency, each with a runnable bad and good version and measured evidence.

The site accompanies the PyCon Hong Kong 2026 talk "Why Your FastAPI Is Not Fast: A Deep Dive into Hidden Bottlenecks". The talk is about what happens inside your route handlers and dependencies. Each claim is backed by code you can run and by output captured from real runs.

What the workshop is ​

The core is a small "Orders API" built with FastAPI, SQLAlchemy 2.0 async, and a payment gateway stand-in. It implements five anti-patterns on purpose:

#Anti-patternThe symptom
AP1Blocking the event loopConcurrent requests run one after another
AP2Dependency-injection lifecycle misuseEvery request pays for a new engine and client
AP3SQLAlchemy lazy loading in asyncA crash, or one query per row (N+1)
AP4Pydantic validation overheadThe same data is validated twice
AP5Connection pool starvationRequests time out waiting for a connection

Each anti-pattern has a bad and a good endpoint on the same live service, so you can compare them without restarting anything. The exception is AP5, where the pool size is fixed when the process starts.

Who it is for ​

  • Python engineers who run FastAPI in production or are about to.
  • Anyone who has seen a "fast" async service behave badly under load and wants to know why.
  • Presenters who want a reproducible demo for their own team.

You do not need prior async expertise, but you should be comfortable reading Python and running a shell command.

What you need ​

RequirementNeeded for
Python 3.12 or newerThe Orders API (requires-python in orders-api-demo/pyproject.toml)
uvInstalling dependencies and running scripts
DockerOnly the Postgres mode, which produces the headline numbers
curlTrying the endpoints

The SQLite mode needs no Docker. See Setup.

How to use this site ​

  • Guide: this section. Setup, architecture, and the baseline API.
  • Anti-patterns: one page per pattern, in the same order each time: the summary, what goes wrong, the bad code, the good code, how to try it, the measured evidence, how to detect it, a checklist, and talking points.
  • Demo: the runbook for presenting or rehearsing the talk, with commands, expected output, and what to do when something breaks.
  • Reference: the checklist, every captured benchmark, profiling tools, endpoints, FAQ, and glossary.

Use the search box in the top bar to find any endpoint, command, or term.

Numbers come from two environments

Every measured number on this site is labelled with where it came from. Postgres capture means the committed output from the Docker setup, which the talk uses. SQLite local means a run on a laptop with the SQLite default. The two differ, and the page explains why. See Benchmarks.

Choose your path ​

Repository map ​

The repository has three layers. This site documents the third one, and links into the other two.

PathWhat it is
orders-api-demo/The runnable FastAPI Orders API, tests, benchmark captures, and scripts
talk/Slides (slides.md, slides.pdf), the presenter guide, and flame-graph assets
site/This documentation site

Released under the MIT License. Speaker: Satyam Soni, PyCon Hong Kong 2026.