{"id":26498854,"url":"https://github.com/justrach/turboapi","last_synced_at":"2026-04-01T18:35:22.698Z","repository":{"id":282507545,"uuid":"948821982","full_name":"justrach/turboAPI","owner":"justrach","description":"FastAPI-compatible Python framework with Zig HTTP core; 7x faster, free-threading native","archived":false,"fork":false,"pushed_at":"2026-03-31T06:19:08.000Z","size":303616,"stargazers_count":862,"open_issues_count":18,"forks_count":26,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-03-31T08:38:27.306Z","etag":null,"topics":["free-threading","http-server","zig"],"latest_commit_sha":null,"homepage":"https://turboapi.trilok.ai","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/justrach.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-15T03:13:32.000Z","updated_at":"2026-03-31T08:36:00.000Z","dependencies_parsed_at":"2025-10-15T08:49:26.280Z","dependency_job_id":"45c3497e-9018-4808-b2c7-def8ab11ffc6","html_url":"https://github.com/justrach/turboAPI","commit_stats":null,"previous_names":["justrach/tatsat","justrach/turboapi"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/justrach/turboAPI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justrach%2FturboAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justrach%2FturboAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justrach%2FturboAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justrach%2FturboAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/justrach","download_url":"https://codeload.github.com/justrach/turboAPI/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justrach%2FturboAPI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290898,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["free-threading","http-server","zig"],"created_at":"2025-03-20T14:50:41.318Z","updated_at":"2026-04-01T18:35:22.686Z","avatar_url":"https://github.com/justrach.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/turbito.png\" alt=\"TurboAPI\" width=\"200\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.org/project/turboapi/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/turboapi.svg?style=flat-square\u0026label=version\" alt=\"PyPI version\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/justrach/turboAPI/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/justrach/turboAPI?style=flat-square\" alt=\"License\" /\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/python-3.14+-blue?style=flat-square\" alt=\"Python 3.14+\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/zig-0.15-f7a41d?style=flat-square\" alt=\"Zig 0.15\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/status-alpha-orange?style=flat-square\" alt=\"Alpha\" /\u003e\n  \u003ca href=\"https://deepwiki.com/justrach/turboAPI\"\u003e\u003cimg src=\"https://deepwiki.com/badge.svg\" alt=\"Ask DeepWiki\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eTurboAPI\u003c/h1\u003e\n\n\u003ch3 align=\"center\"\u003eFastAPI-compatible Python framework. Zig HTTP core. Faster on HTTP-only and uncached HTTP+DB workloads.\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  Drop-in replacement · Zig-native validation · Zero-copy responses · Free-threading · dhi models\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#-status\"\u003eStatus\u003c/a\u003e ·\n  \u003ca href=\"#-quick-start\"\u003eQuick Start\u003c/a\u003e ·\n  \u003ca href=\"#-benchmarks\"\u003eBenchmarks\u003c/a\u003e ·\n  \u003ca href=\"#️-architecture\"\u003eArchitecture\u003c/a\u003e ·\n  \u003ca href=\"#-migrating-from-fastapi\"\u003eMigrate\u003c/a\u003e ·\n  \u003ca href=\"#-why-python\"\u003eWhy Python?\u003c/a\u003e ·\n  \u003ca href=\"#-observability\"\u003eObservability\u003c/a\u003e ·\n  \u003ca href=\"CONTRIBUTING.md\"\u003eContributing\u003c/a\u003e ·\n  \u003ca href=\"SECURITY.md\"\u003eSecurity\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Status\n\n\u003e **Alpha software — read before using in production**\n\u003e\n\u003e TurboAPI works and has 275+ passing tests, but:\n\u003e - **No TLS** — put nginx or Caddy in front for HTTPS\n\u003e - **No slow-loris protection** — requires a reverse proxy with read timeouts\n\u003e - **No configurable max body size** — hardcoded 16MB cap\n\u003e - **WebSocket support** is in progress, not production-ready\n\u003e - **HTTP/2** is not yet implemented\n\u003e - **Free-threaded Python 3.14t** is itself relatively new — some C extensions may not be thread-safe\n\u003e\n\u003e See [SECURITY.md](SECURITY.md) for the full threat model and deployment recommendations.\n\n| What works today                                       | What's in progress                       |\n|--------------------------------------------------------|------------------------------------------|\n| ~140k req/s on uncached HTTP routes (~16x FastAPI)     | WebSocket support                        |\n| FastAPI-compatible route decorators                    | HTTP/2 and TLS                           |\n| Zig HTTP server with 24-thread pool + keep-alive       | Cloudflare Workers WASM target           |\n| Zig-native JSON schema validation (dhi)                | Fiber-based concurrency (via [zag](https://github.com/justrach/zag))  |\n| Zero-alloc response pipeline (stack buffers)           |                                          |\n| Zig-native CORS (0% overhead, pre-rendered headers)    |                                          |\n| Response caching for noargs handlers                   |                                          |\n| Static routes (pre-rendered at startup)                |                                          |\n| Async handler support                                  |                                          |\n| Full security stack (OAuth2, Bearer, API Key)          |                                          |\n| Python 3.14t free-threaded support                     |                                          |\n| Native FFI handlers (C/Zig, no Python at all)          |                                          |\n| Fuzz-tested HTTP parser, router, validator             |                                          |\n\n---\n\n## ⚡ Quick Start\n\n**Requirements:** Python 3.14+ free-threaded (`3.14t`), Zig 0.15+\n\n### Option 1: Docker (easiest)\n\n```bash\ngit clone https://github.com/justrach/turboAPI.git\ncd turboAPI\ndocker compose up\n```\n\nThis builds Python 3.14t from source, compiles the Zig backend, and runs the example app. Hit `http://localhost:8000` to verify.\n\n### Option 2: Local install\n\n```bash\n# Install free-threaded Python\nuv python install 3.14t\n\n# Install turboapi\npip install turboapi\n\n# Or build from source (see below)\n```\n\n```python\nfrom turboapi import TurboAPI\nfrom dhi import BaseModel\n\napp = TurboAPI()\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    quantity: int = 1\n\n@app.get(\"/\")\ndef hello():\n    return {\"message\": \"Hello World\"}\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: int):\n    return {\"item_id\": item_id, \"name\": \"Widget\"}\n\n@app.post(\"/items\")\ndef create_item(item: Item):\n    return {\"item\": item.model_dump(), \"created\": True}\n\nif __name__ == \"__main__\":\n    app.run()\n```\n\n```bash\npython3.14t app.py\n# 🚀 TurboNet-Zig server listening on 127.0.0.1:8000\n```\n\nThe app also exposes an ASGI `__call__` fallback — you can use `uvicorn main:app` to test your route definitions before building the native backend, but this is pure-Python and much slower. For production, always use `app.run()` with the compiled Zig backend.\n\n---\n\n## What's New\n\n### v1.0.27 — release guardrails\n\nRe-cut the patch release after bad `v1.0.25` and `v1.0.26` publishes. `v1.0.27` adds release guardrails so tag pushes fail on version drift and the manual release workflow updates every version declaration consistently.\n\n### v1.0.26 — release metadata fix\n\nRe-cut the patch release after `v1.0.25` published stale `1.0.24` artifacts. `v1.0.26` syncs the package version across all release metadata files and adds a regression test so future release bumps fail fast if those files drift.\n\n### v1.0.25 — yxlyx compatibility cleanup\n\nFixed the top-level password helper exports so `turboapi.hash_password` and `turboapi.verify_password` stay coherent, and removed stale async-handler `xfail` markers for cases that already pass on current `main`. This closes issues #116 and #117.\n\n### v1.0.24 — Zig gzip passthrough fix\n\nRestored gzip middleware body passthrough on the Zig runtime so compressed responses keep both the correct `Content-Encoding: gzip` header and the actual compressed body. This closes issue #96 on current `main`.\n\n### v1.0.23 — Shared Zig core (`turboapi-core`)\n\nExtracted the radix trie router, HTTP utilities, and response cache into a standalone Zig library — [**turboapi-core**](turboapi-core/). Both turboAPI and [merjs](https://github.com/justrach/merjs) now share the same routing and HTTP primitives. Zero performance regression (134k req/s unchanged).\n\n### v1.0.22 — Build fix\n\nRefreshed the pinned `dhi` dependency hash so CI builds the `turbonet` extension on clean runners again.\n\n### v1.0.21 — Compat gap fixes\n\nRestored custom exception handlers, lifespan callables, `/docs` + `/openapi.json` serving, router-level dependencies, and `StaticFiles` mounts in the TestClient/runtime path. Added exact repro coverage for issues #100–#104.\n\n### v1.0.01 — Performance (47k → 150k req/s)\n\nPer-worker `PyThreadState`, `PyObject_CallNoArgs` for zero-arg handlers, tuple response ABI, zero-alloc `sendResponse`, single-parse `model_sync`, static routes, Zig-native CORS, enum handler dispatch, skip header parsing for simple routes, zero-alloc route params, response caching. See [CHANGELOG.md](CHANGELOG.md) for full details.\n\n---\n\n## Benchmarks\n\nBenchmarks are split into three categories and should not be mixed:\n\n- HTTP-only framework overhead\n- end-to-end HTTP + DB\n- driver-only Postgres performance\n\nAll tables below use correct, identical response shapes and explicitly note when caches are disabled.\n\n### HTTP Throughput (no database, cache disabled)\n\n| Endpoint | TurboAPI | FastAPI | Speedup |\n|---|---|---|---|\n| GET /health | 140,586/s | 11,264/s | **12.5x** |\n| GET / | 149,930/s | 11,252/s | **13.3x** |\n| GET /json | 147,167/s | 10,721/s | **13.7x** |\n| GET /users/123 | 145,613/s | 9,775/s | **14.9x** |\n| POST /items | 155,687/s | 8,667/s | **18.0x** |\n| GET /status201 | 146,442/s | 11,991/s | **12.2x** |\n| **Average** | | | **14.1x** |\n\n### End-to-End HTTP + DB (uncached)\n\nSame HTTP routes, same seeded Postgres dataset, TurboAPI response cache off, TurboAPI DB cache off, rate limiting off.\n\nPrimary table below is the median of 3 clean Docker reruns:\n\n| Route | TurboAPI + pg.zig | FastAPI + asyncpg | FastAPI + SQLAlchemy |\n|---|---|---|---|\n| GET /health | **266,351/s** | 9,161/s | 5,010/s |\n| GET /users/{id} varying 1000 IDs | **80,791/s** | 5,203/s | 1,983/s |\n| GET /users?age_min=20 | **71,650/s** | 3,162/s | 1,427/s |\n| GET /search?q=user_42% | **13,245/s** | 3,915/s | 1,742/s |\n\n3-run ranges:\n\n- TurboAPI `GET /users/{id}`: `77,768..94,248/s`\n- FastAPI + asyncpg `GET /users/{id}`: `4,973..5,464/s`\n- FastAPI + SQLAlchemy `GET /users/{id}`: `1,896..2,054/s`\n\n### Driver-Only Postgres\n\nFor pure driver comparisons with no HTTP in the loop, see [`benchmarks/pgbench/BENCHMARKS.md`](benchmarks/pgbench/BENCHMARKS.md).\n\n### Caching\n\nTurboAPI has two optional caching layers. Both can be disabled via environment variables:\n\n| Cache | What it does | Env var to disable |\n|---|---|---|\n| **Response cache** | Caches handler return values after first call. Subsequent requests for the same route skip Python entirely. | `TURBO_DISABLE_CACHE=1` |\n| **DB result cache** | Caches SELECT query results with 30s TTL, 10K max entries, per-table invalidation on writes. | `TURBO_DISABLE_DB_CACHE=1` |\n| **DB cache TTL** | Override the default 30-second TTL. | `TURBO_DB_CACHE_TTL=5` |\n\n**The HTTP-only numbers above are measured with response cache disabled** (`TURBO_DISABLE_CACHE=1`). The end-to-end HTTP+DB table is measured with `TURBO_DISABLE_CACHE=1`, `TURBO_DISABLE_DB_CACHE=1`, and `TURBO_DISABLE_RATE_LIMITING=1`.\n\nFor database benchmarks, `TURBO_DISABLE_DB_CACHE=1` will measure true per-request Postgres performance. With DB caching on, cached reads hit a Zig HashMap instead of Postgres — useful in production but not a fair framework comparison.\n\n### How it works\n\n- **Response caching**: noargs handlers cached after first Python call — subsequent requests skip Python entirely\n- **Zero-arg GET**: `PyObject_CallNoArgs` — no tuple/kwargs allocation\n- **Parameterized GET**: `PyObject_Vectorcall` with Zig-assembled positional args — no `parse_qs`, no kwargs dict\n- **POST (dhi model)**: Zig validates JSON schema **before** acquiring the GIL — invalid bodies return `422` without touching Python\n- **CORS**: Zig-native — headers pre-rendered once at startup, injected via `memcpy`. **0% overhead** (was 24% with Python middleware). OPTIONS preflight handled in Zig.\n\n\n## ⚙️ Architecture\n\n### Shared core: [`turboapi-core`](turboapi-core/)\n\nThe radix trie router, HTTP utilities (`percentDecode`, `queryStringGet`, `statusText`, `formatHttpDate`), and a bounded response cache live in a standalone Zig library — **turboapi-core**. Both turboAPI (this repo) and [merjs](https://github.com/justrach/merjs) import it as a build dependency, so the routing and HTTP parsing logic is shared across both frameworks with zero duplication.\n\n### Request lifecycle\n\nEvery HTTP request flows through the same pipeline. The key idea: Python only runs your business logic. Everything else — parsing, routing, validation, response writing — happens in Zig.\n\n```\n                      ┌──────────────────────────────────────────────────────┐\n                      │                    Zig HTTP Core                     │\n  HTTP Request ──────►│                                                      │\n                      │  TCP accept ──► header parse ──► route match          │\n                       │       (24-thread pool)  (8KB buf)   (radix trie)     │\n                      │                                                      │\n                      │  Content-Length body read (dynamic alloc, 16MB cap)   │\n                      └────────────────────┬─────────────────────────────────┘\n                                           │\n                    ┌──────────────────────┼──────────────────────┐\n                    ▼                      ▼                      ▼\n           ┌───────────────┐    ┌─────────────────────┐   ┌──────────────┐\n           │  Native FFI   │    │    model_sync        │   │  simple_sync │\n           │  (no Python)  │    │                      │   │  body_sync   │\n           │               │    │  JSON parse in Zig   │   │              │\n           │  C handler ───┤    │  dhi schema validate │   │  Acquire GIL │\n           │  direct call  │    │  ▼ fail → 422        │   │  call handler│\n           │  (no GIL)     │    │  ▼ pass → Zig builds │   │  zero-copy   │\n           │               │    │    Python dict from   │   │  write       │\n           └──────┬────────┘    │    parsed JSON        │   └──────┬───────┘\n                  │             │  model(**data)        │          │\n                  │             │  handler(model)       │          │\n                  │             │  zero-copy write      │          │\n                  │             └──────────┬────────────┘          │\n                  │                        │                      │\n                  └────────────────────────┴──────────────────────┘\n                                           │\n                                      ┌────▼─────┐\n                                      │ Response  │\n                                      │ (keep-    │\n                                      │  alive)   │\n                                      └──────────┘\n```\n\n### What \"zero-copy\" means\n\nOn the response path, Zig calls `PyUnicode_AsUTF8()` to get a pointer to the Python string's internal buffer, then calls `write()` directly on the socket. No `memcpy`, no temporary buffers, no heap allocation. The Python string stays alive because we hold a reference to it.\n\n### Handler classification\n\nAt startup, each route is analyzed once and assigned the lightest dispatch path:\n\n| Handler type          | What it skips                                                  | When used                              |\n|-----------------------|----------------------------------------------------------------|----------------------------------------|\n| `native_ffi`          | Python entirely — no GIL, no interpreter                      | C/Zig shared library handlers          |\n| `simple_sync_noargs`  | GIL lookup, tuple/kwargs alloc — uses `PyObject_CallNoArgs`   | Zero-param `GET` handlers              |\n| `model_sync`          | `json.loads` — Zig parses JSON and builds Python dict         | `POST` with a `dhi.BaseModel` param    |\n| `simple_sync`         | header parsing, body parsing, regex                           | `GET` handlers with path/query params  |\n| `body_sync`           | header parsing, regex                                         | `POST` without model params            |\n| `enhanced`            | nothing — full Python dispatch                                | `Depends()`, middleware, complex types  |\n\n### Zig-side JSON parsing (model_sync)\n\nFor `model_sync` routes, the JSON request body is parsed **twice in Zig, zero times in Python**:\n\n1. **dhi validation** — `dhi_validator.zig` parses the JSON and validates field types, constraints (`min_length`, `gt`, etc.), nested objects, and unions. Invalid requests get a `422` without acquiring the GIL.\n2. **Python dict construction** — `jsonValueToPyObject()` in `server.zig` recursively converts the parsed `std.json.Value` tree into Python objects (`PyDict`, `PyList`, `PyUnicode`, `PyLong`, `PyFloat`, `PyBool`, `Py_None`). The resulting dict is passed to the handler as `body_dict`.\n\nThe Python handler receives a pre-built dict and just does `model_class(**data)` — no `json.loads`, no parsing overhead.\n\n---\n\n## 🚀 Features\n\n### Drop-in FastAPI replacement\n\n```python\n# Before\nfrom fastapi import FastAPI, Depends, HTTPException\nfrom pydantic import BaseModel\n\n# After\nfrom turboapi import TurboAPI as FastAPI, Depends, HTTPException\nfrom dhi import BaseModel\n```\n\nEverything else stays the same. Routes, decorators, dependency injection, middleware — all compatible.\n\n### Zig-native validation via [dhi](https://github.com/justrach/dhi)\n\n```python\nfrom dhi import BaseModel, Field\n\nclass CreateUser(BaseModel):\n    name: str = Field(min_length=1, max_length=100)\n    email: str\n    age: int = Field(gt=0, le=150)\n\n@app.post(\"/users\")\ndef create_user(user: CreateUser):\n    return {\"created\": True, \"user\": user.model_dump()}\n```\n\nModel schemas are extracted at startup and compiled into Zig. Invalid requests get rejected with a `422` **before touching Python** — no GIL acquired, no handler called. Valid requests are passed to your handler with a real model instance.\n\n### Async handlers\n\n```python\n@app.get(\"/async\")\nasync def async_handler():\n    data = await fetch_from_database()\n    return {\"data\": data}\n```\n\nAsync handlers are automatically detected and awaited via `asyncio.run()`.\n\n### Full security stack\n\n```python\nfrom turboapi import Depends, HTTPException\nfrom turboapi.security import OAuth2PasswordBearer, HTTPBearer, APIKeyHeader\n\noauth2 = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n@app.get(\"/protected\")\ndef protected(token: str = Depends(oauth2)):\n    if token != \"secret\":\n        raise HTTPException(status_code=401, detail=\"Invalid token\")\n    return {\"user\": \"authenticated\"}\n```\n\nOAuth2, HTTP Bearer/Basic, API Key (header/query/cookie) — all supported with correct status codes (401/403).\n\n### Native FFI handlers\n\nSkip Python entirely for maximum throughput:\n\n```python\n# Register a handler from a compiled shared library\napp.add_native_route(\"GET\", \"/fast\", \"./libhandler.so\", \"handle_request\")\n```\n\nThe Zig server calls the C function directly — no GIL, no interpreter, no overhead.\n\n---\n\n## 🔄 Migrating from FastAPI\n\n### Step 1: Swap the imports\n\n```python\n# Before\nfrom fastapi import FastAPI, Depends, HTTPException, Query, Path\nfrom pydantic import BaseModel\n\n# After\nfrom turboapi import TurboAPI as FastAPI, Depends, HTTPException, Query, Path\nfrom dhi import BaseModel\n```\n\n### Step 2: Use the built-in server\n\n```python\n# FastAPI way (still works)\nif __name__ == \"__main__\":\n    import uvicorn\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n\n# TurboAPI way (20x faster)\nif __name__ == \"__main__\":\n    app.run(host=\"0.0.0.0\", port=8000)\n```\n\n### Step 3: Run with free-threading\n\n```bash\n# Install free-threaded Python\nuv python install 3.14t\n\npython3.14t app.py\n```\n\n---\n\n## Feature Parity\n\n| Feature | Status |\n|---------|--------|\n| Route decorators (@get, @post, etc.) | ✅ |\n| Path parameters with type coercion | ✅ |\n| Query parameters | ✅ |\n| JSON request body | ✅ |\n| Async handlers | ✅ |\n| Dependency injection (`Depends()`) | ✅ |\n| OAuth2 (Password, AuthCode) | ✅ |\n| HTTP Bearer / Basic auth | ✅ |\n| API Key (Header / Query / Cookie) | ✅ |\n| CORS middleware | ✅ |\n| GZip middleware | ✅ |\n| HTTPException with status codes | ✅ |\n| Custom responses (JSON, HTML, Redirect) | ✅ |\n| Background tasks | ✅ |\n| APIRouter with prefixes | ✅ |\n| Native FFI handlers (C/Zig, no Python) | ✅ |\n| Zig-native JSON schema validation (dhi) | ✅ |\n| Zig-side JSON→Python dict (no json.loads) | ✅ |\n| Large body support (up to 16MB) | ✅ |\n| Python 3.14t free-threaded | ✅ |\n| WebSocket support | 🔧 In progress |\n| HTTP/2 + TLS | 🔧 In progress |\n\n---\n\n## 📁 Project Structure\n\n```\nturboAPI/\n├── turboapi-core/              # shared Zig library (also used by merjs)\n│   ├── src/\n│   │   ├── root.zig            # public API surface\n│   │   ├── router.zig          # radix trie with path params + wildcards\n│   │   ├── http.zig            # percentDecode, queryStringGet, statusText, formatHttpDate\n│   │   ├── cache.zig           # bounded thread-safe response cache\n│   │   └── types.zig           # HeaderPair, shared types\n│   ├── build.zig\n│   └── build.zig.zon           # zero dependencies\n├── python/turboapi/\n│   ├── main_app.py             # TurboAPI class (FastAPI-compatible, ASGI __call__)\n│   ├── zig_integration.py      # route registration, handler classification\n│   ├── request_handler.py      # enhanced/fast/fast_model handlers\n│   ├── security.py             # OAuth2, HTTPBearer, APIKey, Depends\n│   ├── version_check.py        # free-threading detection\n│   └── turbonet.*.so           # compiled Zig extension\n├── zig/\n│   ├── src/\n│   │   ├── main.zig            # Python C extension entry\n│   │   ├── server.zig          # HTTP server, thread pool, dispatch, JSON→PyObject\n│   │   ├── dhi_validator.zig   # runtime JSON schema validation\n│   │   ├── db.zig              # TurboPG — Zig-native Postgres driver\n│   │   └── py.zig              # Python C-API wrappers\n│   ├── build.zig               # Zig build system (imports turboapi-core)\n│   ├── build.zig.zon           # dependencies (dhi, pg.zig, turboapi-core)\n│   └── build_turbonet.py       # auto-detect Python, invoke zig build\n├── tests/                      # 275+ tests\n├── benchmarks/\n├── Dockerfile                  # Python 3.14t + Zig 0.15 + turbonet\n├── docker-compose.yml\n└── Makefile                    # make build, make test, make release\n```\n\n\n---\n\n## Building from Source\n\n**Requirements:** [Python 3.14t](https://docs.python.org/3.14/whatsnew/3.14.html) (free-threaded) and [Zig 0.15+](https://ziglang.org/download/)\n\n```bash\n# 1. Clone\ngit clone https://github.com/justrach/turboAPI.git\ncd turboAPI\n\n# 2. Install free-threaded Python (if you don't have it)\nuv python install 3.14t\n\n# 3. Build the Zig native backend (dhi dependency fetched automatically)\npython3.14t zig/build_turbonet.py --install\n\n# 4. Install the Python package\npip install -e \".[dev]\"\n\n# 5. Run tests\npython -m pytest tests/ -p no:anchorpy \\\n  --deselect tests/test_fastapi_parity.py::TestWebSocket -v\n```\n\nOr use the Makefile:\n\n```bash\nmake build       # debug build + install\nmake release     # ReleaseFast build + install\nmake test        # run Python tests\nmake zig-test    # run Zig unit tests\n```\n\nOr just Docker:\n\n```bash\ndocker compose up --build\n```\n\n---\n\n## 🐍 Why Python?\n\nThe \"just use Go/Rust\" criticism is fair for pure throughput. TurboAPI's value proposition is different: **Python ecosystem + near-native HTTP throughput**.\n\n### What you keep with Python\n\n- **ML / AI libraries** — PyTorch, transformers, LangChain, LlamaIndex, etc. None of these exist in Go or Rust at the same maturity level. If your API calls an LLM or does inference, Python is the only practical choice.\n- **ORM ecosystem** — SQLAlchemy, Tortoise, Django ORM, Alembic. Rewriting this in Go is months of work.\n- **Team familiarity** — most backend Python teams can be productive on day one. A Rust rewrite takes 6-12 months and a different hiring profile.\n- **Library coverage** — Stripe SDK, Twilio, boto3, Celery, Redis, every database driver. Go/Rust alternatives exist but are thinner.\n- **FastAPI compatibility** — if you're already on FastAPI, TurboAPI is a one-line import change, not a rewrite.\n\n### When to actually use Go or Rust instead\n\n| Scenario | Recommendation |\n|----------|---------------|\n| Pure JSON proxy, no business logic | Go (net/http or Gin) |\n| Embedded systems, \u003c 1MB binary | Rust |\n| Existing Go/Rust team | Stay in your stack |\n| Need \u003e200k req/s with \u003c0.1ms p99 | Native server, no Python |\n| Need HTTP/2, gRPC today | Go (mature ecosystem) |\n| Heavy Python ML/data dependencies | TurboAPI |\n| FastAPI codebase, need 10-20x throughput | TurboAPI |\n| Background workers + AI inference + HTTP | TurboAPI |\n\n### The realistic throughput story\n\n```\n                     req/s     p50 latency    Python needed?\nGo net/http          250k+     0.05ms         No\nTurboAPI (noargs)    144k      0.16ms         Yes (thin layer)\nTurboAPI (CORS)      110k      0.22ms         Yes\nFastAPI + uvicorn    6-8k      14ms           Yes\nDjango REST          2-4k      25ms+          Yes\n```\n\nTurboAPI won't out-run a native Go server on raw req/s. It closes most of the gap while keeping your Python codebase intact.\n\n---\n\n## 🔭 Observability\n\nTurboAPI handlers are regular Python functions — standard observability tools work without special adapters.\n\n### OpenTelemetry\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor\nfrom opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter\n\nprovider = TracerProvider()\nprovider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))\ntrace.set_tracer_provider(provider)\n\ntracer = trace.get_tracer(__name__)\n\napp = TurboAPI()\n\n@app.get(\"/users/{user_id}\")\ndef get_user(user_id: int):\n    with tracer.start_as_current_span(\"get_user\") as span:\n        span.set_attribute(\"user.id\", user_id)\n        user = db.get(user_id)\n        return user.dict()\n```\n\n### Prometheus\n\n```python\nfrom prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST\nimport time\n\nREQUEST_COUNT = Counter(\"http_requests_total\", \"Total requests\", [\"method\", \"path\", \"status\"])\nREQUEST_LATENCY = Histogram(\"http_request_duration_seconds\", \"Request latency\", [\"path\"])\n\nclass MetricsMiddleware:\n    async def __call__(self, request, call_next):\n        start = time.perf_counter()\n        response = await call_next(request)\n        duration = time.perf_counter() - start\n        REQUEST_COUNT.labels(request.method, request.url.path, response.status_code).inc()\n        REQUEST_LATENCY.labels(request.url.path).observe(duration)\n        return response\n\napp = TurboAPI()\napp.add_middleware(MetricsMiddleware)\n\n@app.get(\"/metrics\")\ndef metrics():\n    from turboapi import Response\n    return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)\n```\n\n### Structured logging\n\n```python\nimport structlog\n\nlog = structlog.get_logger()\n\n@app.get(\"/orders/{order_id}\")\ndef get_order(order_id: int):\n    log.info(\"order.fetch\", order_id=order_id)\n    order = db.fetch(order_id)\n    if not order:\n        log.warning(\"order.not_found\", order_id=order_id)\n        raise HTTPException(status_code=404)\n    return order.dict()\n```\n\nMiddleware-based tracing works today on `enhanced`-path routes (those using `Depends()`, or any route when middleware is added). The Zig fast-path routes bypass the Python middleware stack for throughput — if you need per-request tracing on every route, add a middleware and accept the ~24% throughput overhead.\n\n\n## 🤝 Contributing\n\nOpen an issue before submitting a large PR so we can align on the approach.\n\n```bash\ngit clone https://github.com/justrach/turboAPI.git\ncd turboAPI\nuv python install 3.14t\npython3.14t zig/build_turbonet.py --install   # build Zig backend\npip install -e \".[dev]\"                        # install in dev mode\nmake hooks                                     # install pre-commit hook\nmake test                                      # verify everything works\n```\n\n---\n\n## Credits\n\n- **[dhi](https://github.com/justrach/dhi)** — Pydantic-compatible validation, Zig + Python\n- **[Zig 0.15](https://ziglang.org)** — HTTP server, JSON validation, zero-copy I/O\n- **Python 3.14t** — free-threaded runtime, true parallelism\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustrach%2Fturboapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustrach%2Fturboapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustrach%2Fturboapi/lists"}