---
title: "Client Pool: Pre-Connected Mixnet Clients"
description: "The Nym ClientPool maintains ready-to-use MixnetClient instances, eliminating connection latency for bursty traffic patterns."
schemaType: "TechArticle"
section: "Developers"
lastUpdated: "2026-03-15"
---

# Client Pool

import { Callout } from 'nextra/components'

The `ClientPool` maintains a configurable number of connected ephemeral `MixnetClient` instances, ready for immediate use. This eliminates the connection latency that comes with creating a new client on each request: the gateway handshake, key generation, and topology fetch all happen ahead of time.

## How it works

```mermaid
---
config:
  theme: neo-dark
---
flowchart LR
    BG["Background loop"] -->|creates clients| P["Pool (Vec)"]
    P -->|"get_mixnet_client()"| APP["Your application"]
    APP -->|uses and disconnects| D["Done"]
    BG -->|"pool < reserve? create another"| P
```

1. **Create** the pool with a target reserve size: `ClientPool::new(5)`
2. **Start** the background loop: `pool.start()`. It immediately begins connecting clients
3. **Pop** a client when needed: `pool.get_mixnet_client()` returns `Some(client)` or `None` if the pool is empty
4. **Use** the client normally: send messages, open streams, etc.
5. **Disconnect** the client when done. The background loop notices the pool is below reserve and creates a replacement

Clients are **consumed, not returned**. The pool creates new ones to maintain the reserve. If the pool is empty, you can fall back to `MixnetClient::connect_new()` (slower, but keeps things working).

<Callout type="info">
The `NymProxyClient` (TcpProxy) uses a `ClientPool` internally: one client per incoming TCP connection.
</Callout>

## Quick example

```rust
use nym_sdk::client_pool::ClientPool;
use nym_network_defaults::setup_env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    nym_bin_common::logging::setup_tracing_logger();
    // Load mainnet network defaults into env vars (required by ClientPool)
    setup_env(None::<String>);

    let pool = ClientPool::new(5); // maintain 5 clients in reserve

    let pool_clone = pool.clone();
    tokio::spawn(async move { pool_clone.start().await });

    // Get a client when needed
    if let Some(client) = pool.get_mixnet_client().await {
        println!("Got client: {}", client.nym_address());
        client.disconnect().await;
    }

    pool.disconnect_pool().await;
    Ok(())
}
```

## Further reading

- [Tutorial: Handle bursty traffic](./client-pool/tutorial): step-by-step guide covering pool creation, burst handling, and fallback logic
- [API reference on docs.rs](https://docs.rs/nym-sdk/latest/nym_sdk/client_pool/): type details, method signatures, and architecture docs
- [Example source on GitHub](https://github.com/nymtech/nym/blob/develop/sdk/rust/nym-sdk/examples/client_pool.rs): complete working example
