# Moka Cache Value Types Supported: Trait Bounds and Generic Constraints Explained

> Explore Moka cache value types supported including trait bounds and generic constraints. Store any Clone Send Sync 'static type safely in your cache.

- Repository: [moka-rs/moka](https://github.com/moka-rs/moka)
- Tags: documentation
- Published: 2026-03-07

---

**Moka caches support any value type `V` that implements `Clone + Send + Sync + 'static`, enabling thread-safe storage of everything from primitive strings to complex custom structs.**

The [moka-rs/moka](https://github.com/moka-rs/moka) crate is a high-performance caching library for Rust that uses generic type parameters to accommodate diverse data structures. Whether you are building a synchronous API or an async service, understanding the exact trait requirements for cache values ensures you can store data efficiently without compilation errors.

## Core Trait Requirements for Cache Values

Moka enforces strict compile-time guarantees to maintain thread safety and internal consistency. According to the source code in [`src/sync/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/builder.rs) and [`src/future/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/future/builder.rs), every cache value must satisfy four fundamental bounds.

### Required Traits for All Cache Variants

| Cache API | Required Traits for `V` | Source Location |
|-----------|------------------------|-----------------|
| **Synchronous cache** (`sync::Cache`) | `Clone + Send + Sync + 'static` | [`src/sync/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/builder.rs) (lines 68–73) |
| **Asynchronous cache** (`future::Cache`) | `Clone + Send + Sync + 'static` | [`src/future/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/future/builder.rs) (lines 75–80) |
| **Entry API** (`Cache::entry`) | Inherits from parent cache | `Entry<K, V>` definition |

The `'static` lifetime bound ensures values contain no non-static references, which is essential when the cache may be accessed from arbitrary threads. The `Send` and `Sync` traits guarantee safe transfer and sharing across thread boundaries, while `Clone` enables Moka to return copies to callers without exposing internal mutable references.

## Why the Clone Trait Is Mandatory

All write operations—including `insert`, `get_with`, and `entry` upserts—must return a fresh `V` to the caller while keeping the stored entry alive inside the cache. 

In [`src/sync/base_cache.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/base_cache.rs) and [`src/future/base_cache.rs`](https://github.com/moka-rs/moka/blob/main/src/future/base_cache.rs), the internal implementation relies on `Clone` to produce these copies. Without this trait, Moka cannot safely hand data back to your application thread while maintaining its own internal copy for future cache hits. This design eliminates the need for complex lifetime management or reference counting within the cache structure itself.

## Optional Traits for Advanced Features

While the four core traits enable basic caching, additional capabilities require extra bounds on your value type.

### Debug for Eviction Listeners and Inspection

If you use eviction listeners or call `Cache::debug`, your value must implement `std::fmt::Debug`. The implementation in [`src/sync/cache.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/cache.rs) requires `V: Debug` when formatting the cache state for output. 

### Equality and Hash Constraints

Note that `Eq` and `Hash` are **never** required for values—these constraints apply only to key types (`K`). However, if your eviction listener or invalidation predicate (defined in [`src/sync/invalidator.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/invalidator.rs)) needs to compare values, you may optionally implement these traits for your own logic.

### Weighted Size Calculations

When using a `Weigher` closure to calculate entry sizes, the closure itself must be `Send + Sync + 'static`. Defined in [`src/common/concurrent.rs`](https://github.com/moka-rs/moka/blob/main/src/common/concurrent.rs) as `Arc<dyn Fn(&K, &V) -> u32 + Send + Sync>`, the weigher receives references to keys and values but imposes no additional trait requirements on `V` beyond the core bounds.

## Working with Custom Value Types

You can store complex structures—structs, enums, collections, or `Arc<T>`—as long as they satisfy the core bounds. For types holding non-static references, wrap them in `Arc` or `Box` to make them `'static`.

```rust
use moka::sync::Cache;
use std::sync::Arc;

#[derive(Clone, Debug)]
struct User {
    id: u64,
    name: String,
    permissions: Vec<String>,
}

let cache = Cache::builder()
    .max_capacity(1000)
    .build();

// Storing a custom struct
cache.insert(42, User { 
    id: 42, 
    name: "Alice".into(),
    permissions: vec!["read".into(), "write".into()],
});

// Wrapping non-static data in Arc
let data = "temporary".to_string();
cache.insert(0, Arc::new(data));

```

## Practical Code Examples

### 1. Basic Cache with Primitive Values

Primitive types and standard library collections automatically satisfy the required traits.

```rust
use moka::sync::Cache;

let cache = Cache::builder()
    .max_capacity(100)
    .build();

cache.insert(1, "one".to_string());
assert_eq!(cache.get(&1), Some("one".to_string()));

```

### 2. Async Cache with Custom Structs

The `future::Cache` variant enforces identical trait bounds but requires await points for async operations.

```rust
use moka::future::Cache;
use std::time::{Duration, Instant};

#[derive(Clone, Debug)]
struct Session {
    token: String,
    expires_at: Instant,
}

let cache = Cache::builder()
    .max_capacity(500)
    .time_to_live(Duration::from_secs(3600))
    .build();

cache.insert(123, Session {
    token: "abc123".into(),
    expires_at: Instant::now() + Duration::from_secs(3600),
}).await;

```

### 3. Weighted Cache Implementation

Use a weigher function when cache entries have different memory footprints.

```rust
use moka::sync::Cache;

fn byte_weigher(_k: &usize, v: &Vec<u8>) -> u32 {
    v.len() as u32
}

let cache = Cache::builder()
    .max_capacity(10_000)  // Maximum total weight
    .weigher(byte_weigher)
    .build();

cache.insert(0, vec![0u8; 1024]); // 1 KB entry

```

### 4. Eviction Listener with Debug Output

Eviction listeners require `Debug` to print removed values.

```rust
use moka::sync::Cache;
use moka::notification::RemovalCause;

let cache = Cache::builder()
    .max_capacity(2)
    .eviction_listener(|k, v: &String, cause| {
        println!("Evicted key={:?}, value={:?}, cause={:?}", k, v, cause);
    })
    .build();

cache.insert(1, "first".to_string());
cache.insert(2, "second".to_string());
cache.insert(3, "third".to_string()); // Triggers eviction of key 1 or 2

```

## Key Source Files Reference

Understanding where Moka enforces these constraints helps when debugging trait bound errors:

| File Path | Purpose |
|-----------|---------|
| [`src/sync/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/builder.rs) | Defines `CacheBuilder` and the `V: Clone + Send + Sync + 'static` constraint for synchronous caches |
| [`src/future/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/future/builder.rs) | Async cache builder with identical value type requirements |
| [`src/sync/base_cache.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/base_cache.rs) | Core synchronous cache implementation using generic `V` |
| [`src/future/base_cache.rs`](https://github.com/moka-rs/moka/blob/main/src/future/base_cache.rs) | Async cache core, mirroring generic bounds |
| [`src/common/concurrent.rs`](https://github.com/moka-rs/moka/blob/main/src/common/concurrent.rs) | Contains `Weigher` type definition and concurrency primitives |
| [`src/sync/invalidator.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/invalidator.rs) | Implements invalidation predicates operating on `(&K, &V)` |

## Summary

- **Any type** implementing `Clone + Send + Sync + 'static` can be stored in Moka caches, including both `sync::Cache` and `future::Cache` variants.
- The `Clone` trait is mandatory because Moka returns copies of values on read operations while retaining internal copies.
- **`Debug`** is only required when using eviction listeners or the `Cache::debug` inspection method.
- **Non-static references** must be wrapped in `Arc` or `Box` to satisfy the `'static` lifetime requirement.
- File locations [`src/sync/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/builder.rs) and [`src/future/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/future/builder.rs) contain the definitive trait bounds enforced by the compiler.

## Frequently Asked Questions

### Can I store types with non-static lifetimes in a Moka cache?

No, but you can work around this by wrapping the data in `Arc<T>` or `Box<T>`. The `'static` bound in [`src/sync/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/builder.rs) requires values to own their data or use reference-counted pointers, ensuring thread safety when the cache moves data between threads.

### Do synchronous and asynchronous caches have different value type requirements?

No. Both `sync::Cache` and `future::Cache` require exactly the same trait bounds: `Clone + Send + Sync + 'static`. The [`src/future/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/future/builder.rs) file mirrors the constraints defined in [`src/sync/builder.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/builder.rs), ensuring API consistency across blocking and async contexts.

### Is the `Debug` trait required for all Moka cache values?

Only if you use specific features. The `Debug` bound is enforced when you configure an eviction listener or call the cache's debug formatting methods. Basic insert and get operations do not require `V: Debug` according to the implementation in [`src/sync/cache.rs`](https://github.com/moka-rs/moka/blob/main/src/sync/cache.rs).

### Why does Moka require `Send` and `Sync` for values?

These traits ensure that cached data can safely move between threads and be accessed concurrently. Because Moka uses internal concurrency mechanisms (defined in [`src/common/concurrent.rs`](https://github.com/moka-rs/moka/blob/main/src/common/concurrent.rs)) to handle cache hits and evictions across multiple threads, values must be thread-safe to prevent data races.