[{"data":1,"prerenderedAt":88},["ShallowReactive",2],{"qa-\u002Ffastapi\u002Fdeployment\u002Fuvicorn-gunicorn":3},{"page":4,"siblings":79,"blog":70},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":69,"related":70,"seo":71,"seoDescription":72,"stem":73,"subtopic":74,"topic":75,"topicSlug":76,"updated":77,"__hash__":78},"qa\u002Ffastapi\u002Fdeployment\u002Fuvicorn-gunicorn.md","Uvicorn Gunicorn",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","FastAPI","fastapi",{},true,1,"\u002Ffastapi\u002Fdeployment\u002Fuvicorn-gunicorn",[23,28,32,36,40,44,48,52,57,61,65],{"id":24,"difficulty":25,"q":26,"a":27},"uvicorn-basics","easy","What is Uvicorn and why is it the recommended server for FastAPI?","**Uvicorn** is a lightning-fast ASGI server built on `uvloop` (a C-accelerated\nasyncio event loop) and `httptools`. FastAPI requires an ASGI server because\nit's built on Starlette, which uses the ASGI protocol.\n\n```bash\npip install uvicorn[standard]   # includes uvloop and httptools\nuvicorn app.main:app --host 0.0.0.0 --port 8000\n```\n\nKey flags:\n- `--reload` — hot reload for development\n- `--workers N` — multiple processes (single worker = one event loop)\n- `--host 0.0.0.0` — listen on all interfaces\n- `--port 8000`\n\nRule of thumb: use `uvicorn[standard]` in production for the `uvloop` speedup;\nuse plain `uvicorn` in Docker to keep the image small (uvloop has C deps).\n",{"id":29,"difficulty":14,"q":30,"a":31},"gunicorn-uvicorn-workers","Why combine Gunicorn with Uvicorn workers and how do you configure it?","Uvicorn alone handles one event loop per process. **Gunicorn** is a battle-tested\nprocess manager that handles worker lifecycle (respawning crashed workers,\ngraceful restarts, signal handling). Together they give you:\n- Gunicorn's robust process management.\n- Uvicorn's async event loop per worker.\n\n```bash\npip install gunicorn\ngunicorn app.main:app \\\n    -k uvicorn.workers.UvicornWorker \\\n    --workers 4 \\\n    --bind 0.0.0.0:8000 \\\n    --timeout 120\n```\n\n`UvicornWorker` replaces Gunicorn's default sync worker with an async one.\n\nRule of thumb: use Gunicorn + `UvicornWorker` for traditional deployments on\nVMs\u002Fbare metal; use Uvicorn directly in Kubernetes where the orchestrator handles\npod restarts.\n",{"id":33,"difficulty":14,"q":34,"a":35},"worker-count","How many workers should you run per server for a FastAPI app?","The classic formula: **`workers = 2 × CPU_cores + 1`**.\n\n```bash\n# 4-core machine → 9 workers\ngunicorn app.main:app -k uvicorn.workers.UvicornWorker --workers 9\n```\n\nHowever, FastAPI is async — a single worker handles many concurrent requests\nthrough the event loop. For I\u002FO-bound apps (most web APIs), 2-4 workers per\nmachine is often sufficient:\n\n| App type | Worker count |\n|----------|-------------|\n| Pure async I\u002FO | 2–4 per machine |\n| Mixed sync\u002Fasync | 2 × cores |\n| CPU-bound | 1 per core (use multiprocessing separately) |\n\nRule of thumb: start with `2 × cores + 1`; profile under load and reduce if\nworkers share limited resources (DB connections, RAM).\n",{"id":37,"difficulty":14,"q":38,"a":39},"concurrency-vs-parallelism","What is the difference between concurrency and parallelism in the context of FastAPI?","- **Concurrency**: multiple tasks make progress by interleaving on a single CPU\n  (one event loop thread handles thousands of waiting I\u002FO operations).\n- **Parallelism**: multiple tasks run simultaneously on multiple CPUs (multiple\n  Uvicorn worker processes, each with their own event loop).\n\nFastAPI gives you **concurrency** within a single worker via `async def` handlers.\nYou get **parallelism** by running multiple workers.\n\n```\nWorker 1 (CPU core 1): event loop handles 1000 concurrent requests\nWorker 2 (CPU core 2): event loop handles 1000 concurrent requests\n```\n\nCPU-bound code (heavy computation) blocks a core — neither concurrency nor more\n`async def` helps. Use a thread\u002Fprocess pool or a task queue.\n\nRule of thumb: `async def` handlers add concurrency (better I\u002FO throughput per\nworker); more workers add parallelism (better CPU utilisation).\n",{"id":41,"difficulty":25,"q":42,"a":43},"reload-dev","How do you enable hot reload in Uvicorn for development?","Pass `--reload` flag:\n\n```bash\nuvicorn app.main:app --reload --reload-dir app\n```\n\nOr use the Python API (better for IDEs):\n```python\n# run.py\nimport uvicorn\n\nif __name__ == \"__main__\":\n    uvicorn.run(\"app.main:app\", host=\"0.0.0.0\", port=8000, reload=True)\n```\n\n`--reload-dir app` restricts watching to the `app\u002F` directory, avoiding\nfalse reloads when `.pyc` files or test outputs change.\n\nRule of thumb: never use `--reload` in production — it adds overhead and\nrestarts the process on any file change, including logs and temp files.\n",{"id":45,"difficulty":14,"q":46,"a":47},"docker-fastapi","What is the recommended Dockerfile structure for a FastAPI application?","```dockerfile\nFROM python:3.12-slim\n\nWORKDIR \u002Fapp\n\n# Install dependencies first (layer cached until requirements change)\nCOPY requirements.txt .\nRUN pip install --no-cache-dir -r requirements.txt\n\n# Copy application code\nCOPY .\u002Fapp .\u002Fapp\n\nEXPOSE 8000\n\nCMD [\"uvicorn\", \"app.main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\", \"--workers\", \"4\"]\n```\n\nMulti-stage build for smaller images:\n```dockerfile\nFROM python:3.12-slim AS builder\nRUN pip install --no-cache-dir -r requirements.txt --target \u002Finstall\n\nFROM python:3.12-slim\nCOPY --from=builder \u002Finstall \u002Fusr\u002Flocal\u002Flib\u002Fpython3.12\u002Fsite-packages\nCOPY .\u002Fapp .\u002Fapp\nCMD [\"uvicorn\", \"app.main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\"]\n```\n\nRule of thumb: use `--no-cache-dir` in pip installs to keep image size down;\ncopy `requirements.txt` before source code for layer caching.\n",{"id":49,"difficulty":25,"q":50,"a":51},"health-check","How do you add a health check endpoint in FastAPI for container orchestration?","```python\nfrom fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\n@app.get(\"\u002Fhealth\", include_in_schema=False)\nasync def health():\n    return {\"status\": \"ok\"}\n\n# Liveness (is the process alive?)\n@app.get(\"\u002Fhealth\u002Flive\", include_in_schema=False)\nasync def liveness():\n    return {\"status\": \"alive\"}\n\n# Readiness (is the app ready to serve traffic?)\n@app.get(\"\u002Fhealth\u002Fready\", include_in_schema=False)\nasync def readiness():\n    try:\n        await db.execute(\"SELECT 1\")\n    except Exception:\n        return JSONResponse({\"status\": \"not ready\"}, status_code=503)\n    return {\"status\": \"ready\"}\n```\n\nKubernetes `livenessProbe` uses `\u002Fhealth\u002Flive`; `readinessProbe` uses `\u002Fhealth\u002Fready`.\n\nRule of thumb: readiness should check actual dependencies (DB, cache);\nliveness should only check the process is alive — failing liveness kills the pod.\n",{"id":53,"difficulty":54,"q":55,"a":56},"graceful-shutdown","hard","How does FastAPI\u002FUvicorn handle graceful shutdown?","When Uvicorn receives **SIGTERM** (sent by Kubernetes, Docker, or Gunicorn):\n1. It stops accepting new connections.\n2. Waits for in-flight requests to complete (up to `--timeout-graceful-shutdown` seconds).\n3. Calls the `lifespan` shutdown code (after `yield`).\n4. Closes the event loop and exits.\n\n```bash\nuvicorn app.main:app --timeout-graceful-shutdown 30\n```\n\nIn Kubernetes, set a `preStop` hook to delay pod termination so the load\nbalancer routes traffic away before the pod stops accepting connections:\n\n```yaml\nlifecycle:\n    preStop:\n        exec:\n            command: [\"sleep\", \"5\"]\n```\n\nRule of thumb: always set `--timeout-graceful-shutdown` to slightly less than\nKubernetes' `terminationGracePeriodSeconds` to give in-flight requests time to finish.\n",{"id":58,"difficulty":25,"q":59,"a":60},"environment-variables-uvicorn","How do you pass environment variables to a FastAPI app running in Docker?","Pass them at container run time (don't bake secrets into the image):\n\n```bash\ndocker run -e DATABASE_URL=postgresql:\u002F\u002F... -e SECRET_KEY=... myapp\n```\n\nOr use a `.env` file:\n```bash\ndocker run --env-file .env.production myapp\n```\n\nIn Docker Compose:\n```yaml\nservices:\n    api:\n        image: myapp\n        environment:\n            - DATABASE_URL=postgresql:\u002F\u002Fdb\u002Fmydb\n            - SECRET_KEY=${SECRET_KEY}\n```\n\nIn Kubernetes, use `Secrets` (base64-encoded) for sensitive values:\n```yaml\nenvFrom:\n    - secretRef:\n        name: myapp-secrets\n```\n\nRule of thumb: never embed production secrets in the Docker image or\n`docker-compose.yml` — always inject at runtime from secrets management.\n",{"id":62,"difficulty":54,"q":63,"a":64},"multiple-apps-mount","How do you serve multiple FastAPI apps from a single Uvicorn process?","Mount sub-applications using Starlette's `Mount`:\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette.routing import Mount\nfrom fastapi import FastAPI\n\nv1_app = FastAPI(title=\"API v1\")\nv2_app = FastAPI(title=\"API v2\")\n\n@v1_app.get(\"\u002Fitems\")\nasync def v1_items(): return [{\"version\": \"v1\"}]\n\n@v2_app.get(\"\u002Fitems\")\nasync def v2_items(): return [{\"version\": \"v2\", \"new_field\": True}]\n\n# Root app that routes between them\nroot_app = Starlette(routes=[\n    Mount(\"\u002Fv1\", app=v1_app),\n    Mount(\"\u002Fv2\", app=v2_app),\n])\n```\n\n```bash\nuvicorn main:root_app --port 8000\n# \u002Fv1\u002Fitems → v1_app; \u002Fv2\u002Fitems → v2_app\n# \u002Fv1\u002Fdocs and \u002Fv2\u002Fdocs each work independently\n```\n\nRule of thumb: mount versioned sub-apps when versions differ so significantly\nthat sharing middleware or the OpenAPI schema would be confusing.\n",{"id":66,"difficulty":14,"q":67,"a":68},"ssl-tls-uvicorn","How do you run Uvicorn with SSL\u002FTLS in development?","Pass `--ssl-keyfile` and `--ssl-certfile`:\n\n```bash\n# Generate self-signed cert for dev\nopenssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes\n\nuvicorn app.main:app --ssl-keyfile key.pem --ssl-certfile cert.pem --port 8443\n```\n\nIn production, **don't terminate TLS in Uvicorn** — use Nginx\u002FCaddy\u002FALB in front.\nTLS termination in the reverse proxy lets you use `certbot` for Let's Encrypt,\nhandle certificate rotation without restarting Uvicorn, and offload TLS overhead.\n\nRule of thumb: Uvicorn TLS is fine for internal service-to-service encryption\nor local dev HTTPS; for public-facing production use a reverse proxy for TLS.\n",11,null,{"description":11},"FastAPI Uvicorn and Gunicorn interview questions — workers, concurrency model, process management, Docker deployment and performance tuning.","fastapi\u002Fdeployment\u002Fuvicorn-gunicorn","Uvicorn & Gunicorn","Deployment & Middleware","deployment","2026-06-20","NB_fUy4qlVwanwlzoDBtcJM_FUAdfFUHj-XXR8yQdyc",[80,81,84],{"subtopic":74,"path":21,"order":20},{"subtopic":82,"path":83,"order":12},"Middleware","\u002Ffastapi\u002Fdeployment\u002Fmiddleware",{"subtopic":85,"path":86,"order":87},"Background Tasks","\u002Ffastapi\u002Fdeployment\u002Fbackground-tasks",3,1782244113583]