Clients overview
Celeriant speaks a binary protocol over TCP, with optional TLS and mTLS. Use a client library or the CLI. Do not hand-roll the wire format; the framing, dictionary compression and Identify handshake have sharp edges the libraries already handle.
What exists, and where to get it
| Client | Runtime | Install today |
|---|---|---|
.NET (Celeriant.Client) | net8.0, net9.0, net10.0 | NuGet, 0.8.0: dotnet add package Celeriant.Client. Pulls in Celeriant.Transport at the same version. |
Rust (celeriant_client_tokio) | Rust, tokio | crates.io, 0.2.0: cargo add celeriant_client_tokio celeriant_msg celeriant_wal. The request types and AggregateKey live in the two companion crates. |
CLI / TUI (celeriant_cli) | native binary | Source only: cargo build --release -p celeriant_cli in the server repo. It is not in the container image, which ships only the celeriant server binary. |
Feature matrix
The two libraries cover the same operations. The CLI is where the gaps are.
| .NET | Rust (tokio) | CLI | |
|---|---|---|---|
| Write / read / delete / trim | yes | yes | yes |
| Aggregate details | yes | yes | yes |
| Register schema | yes | yes | yes |
| List orgs / types / aggregates, all shards | streamed | streamed | collected, then printed |
| Auto-paginating read | yes | yes | no, one page |
| Watch (live subscribe) | yes | yes | TUI only |
| Expected version + client idempotency | yes | yes | yes |
| TLS / mTLS | yes | yes | yes |
| API key, RSA-keypair identity | yes | yes | yes |
| Follows leader redirects on writes | yes | yes | TUI only |
| Route reads to followers | opt-in | opt-in | TUI only |
| Request compression | with an identity configured | with an identity configured | with --api-key or a key pair |
Three rows need a sentence each.
Compression rides on the Identify handshake. The server hands over its zstd dictionary in the Identify response, and a connection that never identifies sends and receives everything uncompressed. The .NET and Rust pools identify only when you set an identity (IdentityConfig / with_identity), and the CLI only when you pass identity flags.
The CLI's one-shot commands talk to exactly one node. Each command opens a single connection to --server, with no pool, no redirect and no follower routing. Point a write at a follower and you get the not-leader error back. The TUI uses the Rust pool and gets all three.
An API key and a key pair do different jobs. The API key sets the connection's access level; the key pair proves a client id. When both are configured, .NET sends only the API key, so the key pair proves nothing. Rust and the CLI send both. See Identity and authentication.
RSA-2048, nothing larger
Identify is a fixed-size frame: the body must fit 1007 bytes (1024 less the 17-byte header), uncompressed. An RSA-2048 public key plus its nonce signature fits. RSA-3072 and RSA-4096 do not; the base64 key and signature alone run past the cap. What happens with a larger key depends on the client:
- Rust and the CLI fail every dial with a wire
MessageTooLargeerror before the frame is sent. - .NET does not check. The server refuses the oversized frame and closes the socket, so every connect fails with
ConnectionFailedException, which looks like a network fault. Use RSA-2048.
Which one
- A service on .NET or Rust: that runtime's client. Both pool connections per node, follow leader redirects, and pin reads to the leader unless you opt in to follower reads.
- Operating, scripting, poking at data: the CLI. Reach for the TUI when you want to watch a stream live or need a pool.
The pages here cover the .NET client, the Rust client, and the CLI and TUI.