mio

A fast, low-level, non-blocking I/O library for Rust that wraps epoll, kqueue, and IOCP behind one cross-platform event-polling API.

Library
Cargo
v1.2.2
7,089stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
82/100Excellent
Development Activity84
Maintenance64
Community80
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture84
Code Quality88
Innovation78
Learning Curve55

Mio (Metal I/O) is a low-level, non-blocking I/O library for Rust focused on event notification with as little overhead as possible over the underlying OS abstractions. It exposes a single small API — Poll, Registry, Events, Token, and Interest — that maps directly onto epoll on Linux, kqueue on BSD/macOS, and IOCP on Windows, so application code can register TCP, UDP, and Unix-domain socket sources once and drive them from one readiness-based event loop regardless of platform.

Mio deliberately stays narrow: it has zero required runtime dependencies, allocates nothing at runtime in its hot path, and explicitly omits file I/O, thread pools, and timers, leaving those to higher-level consumers. The most notable of those consumers is Tokio, which uses Mio as its OS-facing reactor — making Mio the foundational I/O layer underneath a large share of the async Rust ecosystem.

What You Get

  • A Poll/Registry/Events/Token/Interest API surface (five names) for registering I/O sources and waiting on readiness events
  • Non-blocking TCP, UDP, and Unix-domain socket primitives in mio::net, gated behind the net feature flag
  • A cross-platform Waker for interrupting a blocked poll() call from another thread
  • Platform-specific extensions (mio::unix, mio::windows) for things like Unix pipes and named pipes, gated behind os-ext
  • Feature-flagged compilation (os-poll, os-ext, net) so consumers only pay for the surface area they actually use

Common Use Cases

  • Building the reactor/event-loop layer underneath a higher-level async runtime (as Tokio does)
  • Writing a high-throughput TCP or UDP server that needs direct control over readiness polling instead of an async runtime’s scheduling overhead
  • Implementing custom protocol servers where predictable, low-allocation I/O behavior matters more than ergonomics
  • Bridging a raw file descriptor or Windows handle into an event loop via SourceFd / NamedPipe

Under The Hood

Architecture Mio’s core types are Poll (src/poll.rs, ~814 lines), which owns a Registry and drives OS event notification, and Events/Token/Interest, which describe what happened and to which registered source. The sys module (src/sys/mod.rs) is the architectural seam: it cfg-selects between sys/unix (epoll/kqueue via a selector submodule), sys/windows (an IOCP-based selector built on the Windows AFD API in afd.rs/iocp.rs/overlapped.rs), sys/wasip1, and a sys/shell fallback that panics unless os-poll is enabled. Application code, net/tcp, net/uds, and waker.rs all funnel through this one re-export boundary, so the platform selector is the single point that has to stay correct for every downstream feature to work; nothing above sys contains OS-specific logic itself.

Tech Stack Rust 2021 edition, MSRV pinned at 1.71 in Cargo.toml, with an explicit per-minor-version MSRV table maintained in the README. The only default dependency is optional log 0.4.8; Unix/Hermit/WASI targets add libc 0.2.183, Windows adds windows-sys 0.61 (scoped to the specific Wdk_*/Win32_* feature sets needed for AFD/IOCP), and WASI adds wasi 0.11.0. There is no async runtime, ORM, or web framework dependency anywhere — Mio sits underneath that layer rather than consuming it. Dev-dependencies (env_logger, rand) support tests and the three bundled examples/ binaries. CI (.github/workflows/ci.yml) builds and tests across the full matrix of supported OS/target combinations.

Code Quality The crate root denies missing_docs, missing_debug_implementations, rust_2018_idioms, unused_imports, and dead_code, and denies warnings under test and doctest builds — a stricter lint posture than most libraries at this level of the stack. Tests live in a dedicated tests/ directory covering polling, TCP/UDP/UDS sockets, the waker, Windows named pipes, and regression cases, backed by a shared tests/util helper module and exercised across platforms in CI. Error handling is consistently std::io::Result-based with errno/OS-error translation isolated inside sys/*, rather than panics (the one intentional exception being the shell implementation’s panic when os-poll is disabled). There is no CONTRIBUTING.md, but contribution and MSRV policy are documented directly in the README.

API Design The public surface is deliberately tiny — five names (Poll, Registry, Events, Token, Interest) cover the entire core workflow of register-then-poll-then-dispatch-on-token, and the README’s quickstart example is the same shape as real usage: no builder chains, no config objects. Doc examples are compiled as doctests (#![doc(test(attr(deny(warnings))))]), so the documentation can’t silently rot out of sync with the API. The unavoidable complexity is conceptual rather than accidental: readiness-based (as opposed to completion-based) I/O semantics take some getting used to, and Mio’s own README candidly points newcomers toward Tokio if they want something friendlier to start with.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search