# Runtimes

> Tako's dual-runtime model — Tokio vs Compio, which transports each supports, TLS and HTTP/2 coverage, and how to switch.

Tako runs on two async runtimes, chosen at build time. The application model —
`Router`, handlers, extractors, middleware, responders — is identical on both.
Transport availability and some middleware adapters differ. Router and route
timeouts work on both; `middleware::timeout::Timeout` exists only on Tokio.

* **Tokio** (default) — multi-threaded, work-stealing scheduler with `Send`
  futures end-to-end. This is what the standalone `Server` builder targets.
* **Compio** (opt-in via the `compio` feature) — single-threaded
  thread-per-core over io\_uring / IOCP / kqueue. Futures are `!Send` and pinned
  to the runtime thread that produced them.

## One runtime selection per build

Without `compio`, Tako selects Tokio. Enabling `compio` switches the HTTP server,
router timers, middleware, queues, and per-thread workers to Compio.
`cargo build --all-features` compiles and selects Compio; the Tokio-only raw
QUIC helper (`RawQuicSession`) is excluded from that build. To use it, choose a
Tokio feature set without `compio`.

## Switching runtimes

By default you get Tokio. To build on Compio, disable defaults and enable the
`compio` feature; add `compio-tls` for TLS on that runtime. Transport features
such as `ws` work on either runtime.

<Tabs items="['Tokio','Compio']">
  <Tab value="Tokio">
    ```toml
    [dependencies]
    tako-rs = "2"
    ```
  </Tab>

  <Tab value="Compio">
    ```toml
    [dependencies]
    tako-rs = { version = "2", default-features = false, features = [
      "compio",
      "compio-tls",
      "ws",
    ] }
    ```
  </Tab>
</Tabs>

The umbrella crate swaps the server type for you: with `compio` on, the
re-exports surface `CompioServer` / `CompioServerBuilder` instead of `Server` /
`ServerBuilder`. The core router API is shared by both. Start servers with the selected builder
and its `try_spawn_*` methods.

## Transport coverage

Every transport runs on both runtimes:

| Protocol                   | Tokio | Compio | Feature flag          |
| -------------------------- | ----- | ------ | --------------------- |
| HTTP/1.1                   | yes   | yes    | *default*             |
| HTTP/2                     | yes   | yes    | `http2`               |
| HTTP/3 (QUIC)              | yes   | yes    | `http3`               |
| TLS (rustls)               | yes   | yes    | `tls` / `compio-tls`  |
| WebSocket                  | yes   | yes    | `ws`                  |
| WebTransport               | yes   | yes    | `webtransport`        |
| SSE                        | yes   | yes    | `sse`                 |
| gRPC (unary and streaming) | yes   | yes    | `grpc`                |
| Raw TCP                    | yes   | yes    | *default*             |
| Raw UDP                    | yes   | yes    | `udp`                 |
| Unix sockets               | yes   | yes    | *default* (unix only) |
| PROXY protocol v1/v2       | yes   | yes    | `proxy-protocol`      |

HTTP/2 over TLS, cleartext h2c, HTTP/3, WebTransport, Unix sockets, and PROXY
protocol are supported on both runtimes. Only the raw QUIC helper
(`RawQuicSession`) is Tokio-only. Raw TCP and UDP use each runtime’s native I/O
API.

## Crossing the runtime boundary internally

Where the framework itself must cross the boundary — for example, hyper's HTTP/2
service running over Compio TLS — it uses `send_wrapper::SendWrapper` to satisfy
hyper's `Send` bound at the type level. The wrapper panics on cross-thread
access, so a misuse becomes a loud panic rather than undefined behaviour. The
soundness contract is per-runtime, not global: every wrapped future is
constructed and polled on the same Compio runtime thread and never handed back
to a multi-threaded Tokio executor.

## Thread-per-core

The `per-thread` and `per-thread-compio` features host the same thread-safe
`Router` on N current-thread workers, fanned out with `SO_REUSEPORT`; Tokio
workers also hand new connections to the least busy worker.
`serve_per_thread(addr, router, config)` blocks until Ctrl+C or SIGTERM and then
drains the workers. `spawn_per_thread(addr, router, config)` returns the worker
thread handles and a `PerThreadShutdown` for explicit control. Enabling
`per-thread-compio` also selects Compio for all shared runtime-dependent code.
These entry points live in `tako-rs-server-pt`.

## Related

* [Installation](/docs/getting-started/installation) — selecting the runtime in
  `Cargo.toml`.
* [Feature reference](/docs/reference/features) — the full runtime-selection
  feature table.
* [Transports](/docs/transports) — per-protocol guides.

Source: https://tako.rust-dd.com/docs/concepts/runtimes