nexar
Library Listed
Distributed runtime that replaces MPI between nodes: point-to-point messages, 11 collectives and RPC over QUIC, with no mpirun or MPI library.
- Downloads
- 1,191
- Dependents
- 5
- Stars
- 5
- Forks
- 1
- Contributors
- 2
- Commits
- 111
- Latest release
- 0.2.1 ·
About
Distributed runtime for Rust. QUIC transport and 11 collectives, with no MPI.
Replaces MPI for inter-node communication. Point-to-point messages, collectives, and RPC run over QUIC without `mpirun` or an MPI library.
Docs · Crate · Collectives · Architecture · Example · Contributing
nexar handles the network layer for distributed Rust programs. It provides point-to-point transfers, collectives, elastic membership, and fault recovery. Workers find each other through a seed node and form a direct peer-to-peer mesh.
- Language: the core
nexarcrate is Rust. It builds onquinn(QUIC),rustls,rkyv, andtokio. Onlyring, a dependency ofrustls, builds bundled C and assembly. There is no Python API. - Data types:
F32,F64,F16,BF16,I8,I32,I64,U8,U32,U64. Reductions:Sum,Prod,Min,Max. - Hardware: the core crate moves host memory with
CpuAdapter.nexar-rdmaadds InfiniBand and RoCE throughlibibverbs, and GPU memory through GPUDirect.nexar-nccluses NCCL inside a node and nexar between nodes. - Used by:
boostrfor distributed inference, behind itsdistributedfeature.
Read the full README
Not supported yet
- Python bindings.
- GPU adapters other than
CudaAdapter(NVIDIA, innexar-rdma). The repository has no ROCm or Intel adapter. - GPU collectives without NCCL.
nexar-ncclrequires NCCL and CUDA.
Quick Start
Add the crates to your project:
cargo add nexar
cargo add tokio --features full
Start a 4-rank local cluster and run an in-place allreduce:
use nexar::{NexarClient, CpuAdapter, DataType, ReduceOp};
use std::sync::Arc;
#[tokio::main]
async fn main() -> nexar::Result<()> {
let adapter = Arc::new(CpuAdapter::new());
let clients = NexarClient::bootstrap_local(4, adapter).await?;
// Each client holds rank 0..3 with connections to all peers.
let client = &clients[0];
assert_eq!(client.rank(), 0);
assert_eq!(client.world_size(), 4);
// Run allreduce in-place across all ranks.
let mut data = vec![1.0f32; 1024];
unsafe {
client.all_reduce(
data.as_mut_ptr() as u64,
1024,
DataType::F32,
ReduceOp::Sum,
).await?;
}
Ok(())
}
The raw-pointer collective methods are unsafe. The caller must keep the buffer valid and sized for count elements of dtype until the call returns.
Multi-host deployment
bootstrap_local runs every rank in one process. For one process per rank, start rank 0 with bootstrap_seed and every other rank with bootstrap_join. Each host sets advertise_addr to its own reachable IP:
use nexar::{ClusterConfig, CpuAdapter, NexarClient};
use std::sync::Arc;
async fn join(is_seed: bool) -> nexar::Result<NexarClient> {
let seed_addr = "10.0.0.1:7000".parse().unwrap();
let cfg = ClusterConfig::new(4)
.with_bind_addr("0.0.0.0:7001".parse().unwrap())
.with_advertise_addr("10.0.0.2:7001".parse().unwrap())
.with_cluster_token(std::env::var("NEXAR_CLUSTER_TOKEN").unwrap());
let adapter = Arc::new(CpuAdapter::new());
if is_seed {
NexarClient::bootstrap_seed(seed_addr, &cfg, adapter).await
} else {
NexarClient::bootstrap_join(seed_addr, &cfg, adapter).await
}
}
Formation runs in four steps:
- Each worker sends
Helloto the seed. The seed assigns ranks and answers withWelcome: the rank and an mTLS certificate from an ephemeral cluster CA. - Each rank binds its mesh listener and reports the address with
MeshListen. - The seed broadcasts the
PeerTableonce every rank reports. Each rank dials higher ranks and accepts lower ranks. - Each rank enters the seed's ready barrier. The bootstrap returns once every rank is ready.
ClusterConfig fields:
| Field | Meaning |
|---|---|
world_size | Number of ranks. Every process uses the same value. |
bind_addr | Local mesh listener. The port carries QUIC (UDP) and the TCP bulk sidecar. |
advertise_addr | Address peers dial. Default: bind_addr. An unspecified IP becomes the IP the seed observes. |
requested_rank | Rank this process asks for. Default: the seed assigns ranks in arrival order. |
cluster_token | Shared secret. Default: NEXAR_CLUSTER_TOKEN. |
join_timeout | Limit for the whole formation. Default: 60 s. |
nexar | NexarConfig of the returned client. |
Set these on every host:
- Seed address: every process uses the address the seed binds. Rank 0 binds it.
- Token: the bootstrap connection does not verify the seed's certificate. The token is the only defense against a stranger who joins or poses as the seed. A bind, seed, or advertise address that is not loopback requires a token, on every
SeedNodeconstructor too. Use the same secret on every process. - Firewall: open the seed port for UDP. Open each rank's mesh port for UDP (QUIC) and TCP (bulk sidecar). With
bind_addrport 0, the ports are ephemeral. Fix the port to write a firewall rule. - NAT and containers: set
advertise_addrto the address peers can reach. With a published container port, map the same port for UDP and TCP. - Sidecar: set the same
enable_tcp_bulk_sidecarandencrypt_bulk_transporton every rank. A mismatch fails formation. Setmax_frame_bytes(default 4 GiB) to the largest message you send; a longer frame closes the sidecar withFrameTooLarge.
Shutdown
Call client.shutdown().await on every rank after its last send and recv, before the process exits. Closing a QUIC connection discards data the peer has not acknowledged, so a rank that exits right after its last collective can lose that collective's final message.
shutdown flushes and closes the TCP sidecars, exchanges a DONE byte with every direct peer, and closes each connection once the peer is done too. A peer that dropped its client counts as done. After the barrier timeout, or the limit passed to shutdown_with_timeout, every connection closes anyway and the call returns ShutdownIncomplete with the peers that did not finish. A peer that answers with another byte, finishes its stream early, or resets it lands in ShutdownIncomplete::bad_signal.
shutdown takes the client by value. A client shared as Arc<NexarClient> needs every other holder dropped first, then Arc::into_inner.
Dropping the last client that shares a mesh closes its connections at once. Unlike shutdown, a drop can lose unacknowledged data.
A failure on one rank aborts formation on every rank with a typed error: RankConflict, ClusterTokenMismatch, ProtocolMismatch, ClusterFormationTimeout, JoinTimeout, or ConnectionFailed { rank }.
Collectives
NexarClient exposes 11 collectives. Each one has an _nb variant that returns a CollectiveHandle. Call wait on the handle to finish the operation.
| Operation | Algorithm |
|---|---|
all_reduce | Ring. Basic ring for small worlds, pipelined ring for large messages |
broadcast | Flat fan-out for small worlds, tree for larger worlds |
all_gather | Ring |
reduce_scatter | Ring |
reduce | Binomial tree |
all_to_all | Each rank sends a distinct chunk to every other rank |
gather | Root receives from all peers concurrently |
scatter | Root sends one chunk to each rank |
scan | Hillis-Steele prefix, O(log N) rounds |
exclusive_scan | Exclusive variant of scan |
barrier | Two-phase below 5 ranks, dissemination at 5 or more ranks |
The client also exposes all_reduce_host, all_reduce_device, and the other _host and _device variants. The _device variants take memory managed by a DeviceAdapter.
Features
- Point-to-point: tagged
sendandrecvbetween any two ranks. A receive takes only its own tag, in send order. See Receive semantics. - Elastic membership:
rebuild_addingandrebuild_excludingchange the communicator at run time. - Fault recovery:
RecoveryPolicy::Automatic,Manual, orAbort. Healthy ranks agree on the failed set and rebuild. - Sparse topologies:
TopologyStrategy::FullMesh,KRegular { degree }, andHypercube. Traffic to non-neighbors relays through peers. - Compressed allreduce:
TopKCompressorand random-K gradient compression. - RPC:
register_rpcregisters a handler by function ID.rpcandrpc_with_timeoutcall it on a rank. Responses match requests by request ID. - Device adapters: the
DeviceAdaptertrait stages device memory for network I/O.CpuAdapterships with nexar.CudaAdapterships withnexar-rdmabehind thegpudirectfeature.
Examples
Runnable examples live in nexar/examples/:
| Example | What it shows |
|---|---|
send_recv | Point-to-point tagged send and recv between two ranks |
allreduce | Ring allreduce (Sum) across 4 ranks |
broadcast | Tree broadcast from root to all ranks |
barrier | Barrier synchronization with staggered arrivals |
rpc | Register a remote function and call it across ranks |
seed_worker | One process per rank: seed and join modes |
Run an example from the repository root:
cargo run -p nexar --example send_recv
cargo run -p nexar --example allreduce
Architecture
seed node (discovery only, no data routing)
│
├── worker 0 ──── worker 1
│ \ /
│ \ /
│ worker 2 ── worker 3
│ ...
└── direct peer-to-peer mesh
Workers connect to the seed to get a rank, a certificate, and the peer table. They then open direct mTLS QUIC connections to their peers. The seed is not on the data path.
Each peer connection runs a router. The router accepts incoming QUIC streams and sends each message to the receiver of its key:
| Receive key | Traffic | Order within the key |
|---|---|---|
LaneKey::Data { comm_id, tag } | Point-to-point send / recv, _iov | Send order (FIFO) |
LaneKey::Tagged { comm_id, tag } | send_bytes_tagged / recv_bytes_tagged | Send order (FIFO) |
LaneKey::Raw { comm_id } | send_bytes / recv_bytes | Send order (FIFO) |
ControlKey (barrier epoch, recovery) | Barrier, recovery, elastic checkpoints | None; epochs keep apart |
| RPC requests, responses by request ID | rpc calls and replies | None |
Receive semantics
- A receive for
(src, key)waits for a message with that key fromsrc. It never takes, or fails on, a message with another key. That message stays queued for its own receiver. - Ordered: the messages of one byte lane from one sender, in the order their sends started on the connection. Each communicator (root, split, rebuilt) has its own tag space.
- Not ordered: different keys, different senders, control messages within one key, and traffic that relays through other ranks in a sparse topology.
- Each key queues
NexarConfig::recv_queue_depthmessages per peer (default 256). A message past that waits unread in its QUIC stream, and QUIC flow control slows its sender. Other keys from the same peer go on while the peer's open streams stay under the QUIC limit of 1024. - A send that fails or is cancelled does not stall the lane. The sender reports its sequence number in a skip notice, and later messages pass it.
- When a peer disconnects, receivers first get the complete messages already queued, then
NexarError::PeerDisconnected. - A message longer than
NexarConfig::max_frame_bytesis refused before any allocation: the router stops its stream, logsFrameTooLarge, and the sender's write fails. The router of each peer reads at mostNexarConfig::recv_inflight_bytesof payload at once (default 4 GiB). A message past that waits unread in its QUIC stream. A message longer than the budget reads alone. - The receiver refuses a sequence number 65536 or more past the lowest unknown one. A hostile peer cannot grow the reorder state.
- Receives are cancel-safe: a receive dropped by a timeout consumes nothing.
- The TCP bulk sidecar that collectives use is one ordered TCP stream per peer. A lagging tag on it delays the tags behind it.
Stream protocol
Each QUIC unidirectional stream starts with a 1-byte tag:
| Tag | Stream content |
|---|---|
0x01 | Framed message: 8-byte length, then a serialized NexarMessage |
0x05 | Sequenced bytes: lane kind (1 byte), comm_id (8), tag (8), sequence number (8), length (8), then the payload |
0x06 | Skip notice: count (4 bytes), then that many 8-byte sequence numbers the sender abandoned |
Integers are little-endian. One counter per connection numbers every sequenced message.
Messages use rkyv serialization.
Crates
| Crate | What it provides | Native dependencies |
|---|---|---|
nexar | Core runtime: QUIC transport, collectives, RPC | ring builds bundled C and assembly |
nexar-rdma | RDMA transport for InfiniBand and RoCE | libibverbs (rdma-core) |
nexar-rdma + gpudirect | GPU memory to RDMA NIC, CudaAdapter | libibverbs and CUDA runtime |
nexar-nccl | Hierarchical communicator: NCCL intra-node, nexar inter-node | CUDA runtime and NCCL |
Build each crate from the repository root:
cargo build -p nexar --release
cargo build -p nexar-rdma --release
cargo build -p nexar-rdma --release --features gpudirect
cargo build -p nexar-nccl --release
Requires Rust 1.89 or later. See CONTRIBUTING.md for test and lint commands.
When to Use nexar
Use nexar when:
- You need collectives such as allreduce or broadcast across machines.
- You want async, non-blocking communication in Rust.
- You want to avoid MPI installation,
mpirun, and C FFI. - You are building distributed ML training or inference.
Use NCCL directly when:
- All GPUs sit in one machine. NCCL uses the local interconnect without a network hop.
Contributing
Contributions are welcome. See CONTRIBUTING.md for conventions and checks.
Questions and design discussion happen on Discord.
License
Licensed under Apache-2.0. See LICENSE.
Compatibility
- Runs on
- CUDA
What shows it
- CUDA: nexar-nccl dependency cudarc, nexar-rdma feature gpudirect (dependency cudarc)
- Native code
- Required
- Binds native code: ring
- Build uses a native toolchain: bindgen, pkg-config
- Python bindings
- No Python binding crate found
- License
- Apache-2.0
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Distributed runtime that replaces MPI between nodes: point-to-point messages, 11 collectives and RPC over QUIC, with no mpirun or MPI library. |
1,191 downloads over 30 days | 5 | 5 | 0.2.1 | CUDA | Binds native code: ring. Build uses a native toolchain: bindgen, pkg-config | Apache-2.0 |
|
boostr Listed
ML framework on numr for training and inference on CPU, CUDA and WebGPU: attention, quantization, inference scheduling and distributed execution. Models include LLaMA, Mamba2, Qwen3.5, Whisper, Kokoro, VITS, VoxCPM2, Silero VAD, CLAP and super-resolution. Loads SafeTensors and GGUF. |
1,265 downloads over 30 days | 7 | 20 | 0.11.2 | CUDA, WebGPU | Binds native code: ring (feature distributed) | Apache-2.0 |
|
Write and read tensorboard files. Python bindings |
445 downloads over 30 days | 3 | 23 | 0.1.1 | GPU support unknown | No native code found | Apache-2.0 OR MIT |
|
A neural network implementation with a focus on cache-efficiency and sequential performance. |
87 downloads over 30 days | 0 | 41 | 0.4.2 | GPU support unknown | No native code found | Apache-2.0 OR MIT |
|
rust-lstm Listed
A complete LSTM neural network library with training capabilities, multiple optimizers, and peephole variants. |
15 downloads over 30 days | 0 | 24 | 0.10.0 | GPU support unknown | No native code found | MIT |
|
HAL: a machine learning library that is able to run on Nvidia, OpenCL or CPU BLAS based compute backends. It currently provides stackable classical neural networks, RNN's and soon to be LSTM's. |
2 downloads over 30 days | 0 | 92 | 0.2.0 | GPU support unknown | No native code found | BSD-3-Clause |
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 0 active dependents and 0 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 5 stars, 1 fork and 2 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 6 Nov 2026, 3 days ago. The rules expect an update within 365 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.2.1 base 300, capped at 5 releases = 250, raised to the 365-day floor: E = 365 daysdormancy: last activity 2026-11-06, 3 days ago, E = 365: activefeatured: not featured: active_users 0 < 11 and new_adopters 0 < 9 and repository route stars 5 (needs 4539), forks 1 (needs 434), contributors 2 (needs 79)listed: listed: no archive, new or featured rule applies
Crates3 crates
- nexar Primary
- nexar-nccl
- nexar-rdma
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: written for the catalogue
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption0 active dependents, 0 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 0 | crates.io database dump | Yes | |
| New dependents (365 days) | 0 | crates.io database dump | Yes | |
| Peak active dependents | 0 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 3 days ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-06 | GitHub repository | Yes | |
| Latest release | 2026-11-06 | crates.io database dump | Yes | |
| First release | 2026-03-14 | crates.io database dump | Yes | |
| Latest version | 0.2.1 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 0 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 0 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution5 releases, 1,191 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 5 | crates.io database dump | Yes | |
| Downloads over 30 days | 1191 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository5 stars, 1 forks, 2 contributors, 111 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 5 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 1 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 2 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 111 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | CUDA | crates.io database dump | No | |
| What shows each backend | CUDA: nexar-nccl dependency cudarc, nexar-rdma feature gpudirect (dependency cudarc) | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | Binds native code: ring. Build uses a native toolchain: bindgen, pkg-config | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 5 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.