a cross-platform (including Wasm!) networking library built in Rust. Intended to make multiplayer game development dead-simple & lightning-fast
Rust
1,183
2,315 commits
updated Oct 12, 2026
Server-authoritative entity replication and typed message passing for multiplayer games in Rust, running on native (UDP) and browser (WebRTC).
naia lets you define a shared Protocol — a compile-time list of replicated
component types, message types, and channel configurations — that both the
server and the client agree on. Given that protocol:
send_all_packets every tick. naia diffs changed fields
and delivers them to every in-scope client automatically.naia is ECS-agnostic. Bevy and macroquad adapters are included; the core crate
works with any entity type that is Copy + Eq + Hash + Send + Sync.
The internal networking model follows the Tribes 2 Networking Model.
| Crate | Role | Add as a dependency when… |
|---|---|---|
naia-shared | Protocol definition, component derives, channel types | You are writing the shared protocol crate |
naia-server | Core server | Writing a server without Bevy |
naia-client | Core client | Writing a client without Bevy or macroquad |
naia-bevy-server | Bevy server adapter | Using Bevy on the server |
naia-bevy-client | Bevy client adapter | Using Bevy on the client |
Protocol value; a hash mismatch during the handshake causes
rejection.Copy + Eq + Hash value your world allocates. naia tracks
which entities are replicated and to whom, but never allocates them itself.take_tick_events advances the tick
counter. TickBuffered channels deliver client input at the correct server
tick for prediction and rollback.Delegated,
allowing a client to request write authority. The server grants or denies
and can revoke at any time.For the full mental-model guide, see docs/CONCEPTS.md.
# shared/Cargo.toml
[dependencies]
naia-shared = "0.24"
# server/Cargo.toml
[dependencies]
naia-server = "0.24"
naia-shared = { path = "../shared" }
# client/Cargo.toml
[dependencies]
naia-client = "0.24"
naia-shared = { path = "../shared" }
See demos/basic/ for a minimal working example.
# shared/Cargo.toml
[dependencies]
naia-shared = "0.24"
# server/Cargo.toml
[dependencies]
naia-bevy-server = "0.24"
naia-shared = { path = "../shared" }
# client/Cargo.toml
[dependencies]
naia-bevy-client = "0.24"
naia-shared = { path = "../shared" }
See demos/bevy/ for a complete Bevy demo.
# client/Cargo.toml
[dependencies]
naia-macroquad-client = "0.24"
naia-shared = { path = "../shared" }
See demos/macroquad/ for a macroquad demo.
| Mode | Ordering | Reliability | Canonical use |
|---|---|---|---|
UnorderedUnreliable | None | None | High-frequency telemetry |
SequencedUnreliable | Newest-wins | None | Position updates (stale ok) |
UnorderedReliable | None | Guaranteed | One-off notifications |
OrderedReliable | FIFO | Guaranteed | Chat, game events |
TickBuffered | Per-tick | Guaranteed | Client input for prediction |
| Bidirectional + Reliable | FIFO | Guaranteed | Request / response pairs |
| Target | Transport | Notes |
|---|---|---|
| Linux / macOS / Windows | UDP | naia-socket-native |
Browser (wasm32-unknown-unknown) | WebRTC data channel | Enable wbindgen feature; build with wasm-pack or trunk |
| iOS / Android (native) | — | Not yet supported — blocked on transport_quic; see FEATURES.md |
| iOS / Android (via WebView) | WebRTC data channel | Run the WASM client inside WKWebView (iOS) or Android WebView; same build as the browser target |
The server always runs natively. Only the client needs WebRTC support for browser targets.
Steam relay (ISteamNetworkingSockets): Not built-in. The Socket trait is
pluggable — a community crate can add Steam networking without modifying naia
core.
| You know… | naia equivalent | Key difference |
|---|---|---|
renet NetworkedEntity / RenetServer | Server<E> + #[derive(Replicate)] | naia replicates ECS state automatically (diff + send); renet is message-only |
renet send_message / receive_message | server.send_message::<Ch, M>() | naia wraps channels as typed Rust generics |
renet ClientId | UserKey | Same concept — opaque handle to a connected client |
lightyear Replicate component | #[derive(Replicate)] on a struct | naia is ECS-agnostic; lightyear is Bevy-only |
lightyear ComponentRegistry | Protocol::add_component::<C>() | Same idea; naia uses a builder pattern |
lightyear InputChannel / predicted input | TickBuffered channel + receive_tick_buffer_messages | naia delivers client input at the matching server tick for rollback |
lightyear Predicted / Interpolated | not built-in | naia supplies the data; you write the prediction/interpolation logic (see PREDICTION.md) |
bevy_replicon Replication marker | server.spawn_entity() + #[derive(Replicate)] | naia has fine-grained per-user scope control via rooms + UserScopeMut |
| bevy_replicon visibility filter | server.user_scope_mut(&user) / rooms | naia: rooms = coarse; user-scope = fine-grained |
(top 24 of 31)
6,580 followers · starred Mar 2026
805 followers · starred Apr 2024
22 followers · starred Feb 2026
359 followers · starred Jun 2023
a cross-platform (including Wasm!) networking library built in Rust. Intended to make multiplayer game development dead-simple & lightning-fast
Rust
1,183
2,315 commits
updated Oct 12, 2026
Server-authoritative entity replication and typed message passing for multiplayer games in Rust, running on native (UDP) and browser (WebRTC).
naia lets you define a shared Protocol — a compile-time list of replicated
component types, message types, and channel configurations — that both the
server and the client agree on. Given that protocol:
send_all_packets every tick. naia diffs changed fields
and delivers them to every in-scope client automatically.naia is ECS-agnostic. Bevy and macroquad adapters are included; the core crate
works with any entity type that is Copy + Eq + Hash + Send + Sync.
The internal networking model follows the Tribes 2 Networking Model.
| Crate | Role | Add as a dependency when… |
|---|---|---|
naia-shared | Protocol definition, component derives, channel types | You are writing the shared protocol crate |
naia-server | Core server | Writing a server without Bevy |
naia-client | Core client | Writing a client without Bevy or macroquad |
naia-bevy-server | Bevy server adapter | Using Bevy on the server |
naia-bevy-client | Bevy client adapter | Using Bevy on the client |
Protocol value; a hash mismatch during the handshake causes
rejection.Copy + Eq + Hash value your world allocates. naia tracks
which entities are replicated and to whom, but never allocates them itself.take_tick_events advances the tick
counter. TickBuffered channels deliver client input at the correct server
tick for prediction and rollback.Delegated,
allowing a client to request write authority. The server grants or denies
and can revoke at any time.For the full mental-model guide, see docs/CONCEPTS.md.
# shared/Cargo.toml
[dependencies]
naia-shared = "0.24"
# server/Cargo.toml
[dependencies]
naia-server = "0.24"
naia-shared = { path = "../shared" }
# client/Cargo.toml
[dependencies]
naia-client = "0.24"
naia-shared = { path = "../shared" }
See demos/basic/ for a minimal working example.
# shared/Cargo.toml
[dependencies]
naia-shared = "0.24"
# server/Cargo.toml
[dependencies]
naia-bevy-server = "0.24"
naia-shared = { path = "../shared" }
# client/Cargo.toml
[dependencies]
naia-bevy-client = "0.24"
naia-shared = { path = "../shared" }
See demos/bevy/ for a complete Bevy demo.
# client/Cargo.toml
[dependencies]
naia-macroquad-client = "0.24"
naia-shared = { path = "../shared" }
See demos/macroquad/ for a macroquad demo.
| Mode | Ordering | Reliability | Canonical use |
|---|---|---|---|
UnorderedUnreliable | None | None | High-frequency telemetry |
SequencedUnreliable | Newest-wins | None | Position updates (stale ok) |
UnorderedReliable | None | Guaranteed | One-off notifications |
OrderedReliable | FIFO | Guaranteed | Chat, game events |
TickBuffered | Per-tick | Guaranteed | Client input for prediction |
| Bidirectional + Reliable | FIFO | Guaranteed | Request / response pairs |
| Target | Transport | Notes |
|---|---|---|
| Linux / macOS / Windows | UDP | naia-socket-native |
Browser (wasm32-unknown-unknown) | WebRTC data channel | Enable wbindgen feature; build with wasm-pack or trunk |
| iOS / Android (native) | — | Not yet supported — blocked on transport_quic; see FEATURES.md |
| iOS / Android (via WebView) | WebRTC data channel | Run the WASM client inside WKWebView (iOS) or Android WebView; same build as the browser target |
The server always runs natively. Only the client needs WebRTC support for browser targets.
Steam relay (ISteamNetworkingSockets): Not built-in. The Socket trait is
pluggable — a community crate can add Steam networking without modifying naia
core.
| You know… | naia equivalent | Key difference |
|---|---|---|
renet NetworkedEntity / RenetServer | Server<E> + #[derive(Replicate)] | naia replicates ECS state automatically (diff + send); renet is message-only |
renet send_message / receive_message | server.send_message::<Ch, M>() | naia wraps channels as typed Rust generics |
renet ClientId | UserKey | Same concept — opaque handle to a connected client |
lightyear Replicate component | #[derive(Replicate)] on a struct | naia is ECS-agnostic; lightyear is Bevy-only |
lightyear ComponentRegistry | Protocol::add_component::<C>() | Same idea; naia uses a builder pattern |
lightyear InputChannel / predicted input | TickBuffered channel + receive_tick_buffer_messages | naia delivers client input at the matching server tick for rollback |
lightyear Predicted / Interpolated | not built-in | naia supplies the data; you write the prediction/interpolation logic (see PREDICTION.md) |
bevy_replicon Replication marker | server.spawn_entity() + #[derive(Replicate)] | naia has fine-grained per-user scope control via rooms + UserScopeMut |
| bevy_replicon visibility filter | server.user_scope_mut(&user) / rooms | naia: rooms = coarse; user-scope = fine-grained |
(top 24 of 31)
6,580 followers · starred Mar 2026
805 followers · starred Apr 2024
22 followers · starred Feb 2026
359 followers · starred Jun 2023