Skip to main content

A pure-Python HTTP framework built for free-threaded Python

Project description

Karak

⚠️ Experimental: This project is a proof-of-concept exploring free-threaded Python (PEP 703) for HTTP frameworks. Not production-ready.

A pure-Python HTTP framework built for free-threaded Python 3.13+. No async/await — just threads with true parallelism.

2-5x faster than FastAPI on real workloads.

Website: karak.dev

Requirements

  • Python 3.13+ with free-threading enabled (python3.13t)
  • uv package manager

Installation

uv add karak

uv add karak[fast]

Development Setup

git clone https://github.com/grandimam/karak.git
cd karak

# Install
uv sync

# Run
uv run python examples/basic.py

# Test
curl http://localhost:8000/
curl http://localhost:8000/items/1
curl -X POST http://localhost:8000/items -H "Content-Type: application/json" -d '{"name":"Widget","price":9.99}'

Running Benchmarks

# Install dev dependencies
uv sync --dev

# Run benchmark
uv run python benchmarks/run_benchmark.py 1000 10

Quick Start

from typing import Annotated
from pydantic import BaseModel
from karak import Karak, Depends

app = Karak()

class Item(BaseModel):
    name: str
    price: float

@app.get("/")
def index() -> dict:
    return {"message": "Hello, World!"}

@app.get("/items/{item_id}")
def get_item(item_id: int) -> dict:
    return {"id": item_id}

@app.post("/items")
def create_item(body: Item) -> Item:
    return body

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8000, workers=4)

Features

  • Pure Python: No C extensions, no Rust, no Cython
  • Free-threaded: True parallelism without the GIL (Python 3.13t)
  • Type-driven: Pydantic models auto-parsed from request body
  • Dependency injection: Depends() with request-scoped caching
  • HTTP Keep-alive: Connection reuse for high throughput
  • Radix tree router: O(1) route matching
  • orjson support: Optional 3-5x faster JSON serialization
  • Minimal: ~500 lines of code in 5 files

Benchmarks

System

Component Value
CPU Apple M2 Pro
Cores 12
Python 3.13.0 (free-threaded)
Platform Darwin arm64

High Concurrency (2000 requests, 100 concurrent clients)

Scenario Free Threaded (16 threads) FastAPI (async) Difference
JSON 8,418 req/s 4,509 req/s Free Threaded: +87%
CPU Bound 1,425 req/s 266 req/s Free Threaded: +435%

Standard Load (1000 requests, 20 concurrent clients)

Scenario Free Threaded (4 threads) FastAPI (async) Difference
JSON 9,287 req/s 4,377 req/s Free Threaded: +112%
DB Query 8,284 req/s 2,302 req/s Free Threaded: +260%
CPU Bound 880 req/s 264 req/s Free Threaded: +233%

Thread Scaling (CPU-bound workload)

Workers req/s Scaling
4 608 1.0x
8 1,172 1.9x
16 1,297 2.1x
32 1,391 2.3x

Analysis

  • I/O-bound (JSON, DB): 2-3.5x faster due to simpler threading model and shared memory
  • CPU-bound: 5x faster — free-threaded Python enables true parallelism while async is single-threaded
  • Scales with cores: Adding threads directly improves CPU-bound throughput
  • Latency: Karak achieves lower p99 latency under load (no async task scheduling overhead)

Architecture

┌─────────────────────────────────────────────────────────┐
│                       Karak App                         │
│              (app.py: DI, validation, handlers)         │
├─────────────────────────────────────────────────────────┤
│                     Radix Router                        │
│              (router.py: O(1) route matching)           │
├─────────────────────────────────────────────────────────┤
│                    Request / Response                   │
│               (types.py: dataclasses)                   │
├─────────────────────────────────────────────────────────┤
│                      HTTP Parser                        │
│            (http.py: parse/write HTTP/1.1)              │
├─────────────────────────────────────────────────────────┤
│                   ThreadPoolExecutor                    │
│         (server.py: sockets, keep-alive, workers)       │
└─────────────────────────────────────────────────────────┘

Project Structure

src/karak/
├── __init__.py   # exports
├── app.py        # Karak, Depends, DI resolution
├── router.py     # RadixRouter, O(1) matching
├── types.py      # Request, Response, HTTPException
├── server.py     # Server, ThreadPool, keep-alive
└── http.py       # HTTPParser, write_response

Why Free-Threaded Python?

Traditional Python has the GIL (Global Interpreter Lock), which prevents true parallelism in threads. Web frameworks work around this using:

  • Async/await (FastAPI, Starlette): Cooperative multitasking
  • Multiprocessing (Gunicorn, uvicorn): Separate processes with IPC overhead

Free-threaded Python (PEP 703) removes the GIL, enabling:

  • Simple synchronous code that runs in parallel
  • Shared memory between threads (no serialization)
  • Lower overhead than multiprocessing

Limitations

  • Experimental and not battle-tested
  • HTTP/1.1 only (no HTTP/2, no WebSocket)
  • No middleware system (yet)
  • C extensions with internal locks don't parallelize

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

karak-0.1.0.tar.gz (25.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

karak-0.1.0-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

File details

Details for the file karak-0.1.0.tar.gz.

File metadata

  • Download URL: karak-0.1.0.tar.gz
  • Upload date:
  • Size: 25.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for karak-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ed2a7cdc74defe480f43ec13593cab7a6ed51c44d2c69017aa51e0fdc0b87318
MD5 85d14b065135c458e60e6d88b78cf2b4
BLAKE2b-256 9a288d707a0fb0e8da22cc11ecd4b8e26baf52e2471ac542a844b7ec75ac03ce

See more details on using hashes here.

File details

Details for the file karak-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: karak-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.0

File hashes

Hashes for karak-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 460f2efd4cedb0075d6bc931ca881951464d89367a08b2adaa392bc18fe24e32
MD5 cfbb51deaf75636f22f42ce2a235a170
BLAKE2b-256 46fd1201107cccfb2a35d845045dabc71ed33abd6cb7bda42cafd6d90b665d00

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page