---
title: "List operations"
description: "Guide to the Rust client's operations::lists builders for server-side list CDT operations with Client::operate()."
---

# List operations

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

A **list bin** stores an ordered collection of values. Aerospike’s list CDT (complex data type) operations let the server add, read, and remove individual list elements in a single round trip, without the client reading the whole bin first.

This matters because [`Client::put`](https://docs.rs/aerospike/latest/aerospike/struct.Client.html#method.put) **always replaces the full bin value**. Calling `put()` a second time with a new `Vec<Value>` does not append to the existing list. It overwrites it. To add items to a list bin that may already exist, without a read-modify-write round trip, use the `aerospike::operations::lists` builders with [`Client::operate()`](https://aerospike.com/docs/develop/client/rust/usage/atomic/multi).

## Setup

```rust
use aerospike::operations::lists;

use aerospike::{as_key, Client, ClientPolicy, ListPolicy, ListReturnType, Value, WritePolicy};

let client = Client::new(&ClientPolicy::default(), &"127.0.0.1:3000").await?;

let key = as_key!("test", "carts", "cart:1");

let policy = ListPolicy::default();
```

> 📖 **API reference**: [`Client::new`](https://docs.rs/aerospike/latest/aerospike/struct.Client.html#method.new) | [`operations::lists`](https://docs.rs/aerospike/latest/aerospike/operations/lists/index.html) | [`ListPolicy`](https://docs.rs/aerospike/latest/aerospike/operations/lists/struct.ListPolicy.html)

## Append to a list bin

`lists::append` appends a single value to a list bin and creates the bin (and an empty list) if it doesn’t exist yet. No read is required first. Call it again later and it appends again, rather than overwriting:

```rust
let ops = vec![lists::append(&policy, "items", Value::from("apple"))];

client.operate(&WritePolicy::default(), &key, &ops).await?;

// Later, in a separate call. This appends "banana", it does not replace "apple".

let ops = vec![lists::append(&policy, "items", Value::from("banana"))];

client.operate(&WritePolicy::default(), &key, &ops).await?;

// items is now ["apple", "banana"]
```

> 📖 **API reference**: [`operations::lists::append`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.append.html) | [`Client::operate`](https://docs.rs/aerospike/latest/aerospike/struct.Client.html#method.operate)

To append more than one value in a single call, use `append_items`:

```rust
let ops = vec![lists::append_items(

    &policy,

    "items",

    vec![Value::from("cherry"), Value::from("date")],

)];

client.operate(&WritePolicy::default(), &key, &ops).await?;
```

> 📖 **API reference**: [`operations::lists::append_items`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.append_items.html)

## Read the list size

`lists::size` returns the number of elements in a list bin. Combine it with an append in the same `operate()` call to append and confirm the new length in one round trip:

```rust
let ops = vec![

    lists::append(&policy, "items", Value::from("apple")),

    lists::size("items"),

];

let record = client.operate(&WritePolicy::default(), &key, &ops).await?;

// record.results holds one answer per operation, in order; the size is the second.

let results = record.results.unwrap();

println!("list size: {:?}", results[1]);
```

> 📖 **API reference**: [`operations::lists::size`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.size.html) | [`Record::results`](https://docs.rs/aerospike/latest/aerospike/struct.Record.html#structfield.results)

## Read elements back

`lists::get` and `lists::get_range` read one element or a range of elements without removing them:

```rust
let ops = vec![lists::get_range("items", 0, 2)]; // first two elements

let record = client.operate(&WritePolicy::default(), &key, &ops).await?;

println!("{:?}", record.results.unwrap()[0]);
```

> 📖 **API reference**: [`operations::lists::get`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.get.html) | [`operations::lists::get_range`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.get_range.html)

## Remove elements

`lists::pop` removes and returns the element at an index. `lists::remove_by_value` removes every occurrence of a value and takes a `ListReturnType` that selects what the server reports about the removed items:

```rust
let ops = vec![lists::pop("items", 0)]; // remove and return the first element

client.operate(&WritePolicy::default(), &key, &ops).await?;

// Remove every "banana"; COUNT asks the server to return how many were removed.

let ops = vec![lists::remove_by_value("items", Value::from("banana"), ListReturnType::COUNT)];

client.operate(&WritePolicy::default(), &key, &ops).await?;
```

> 📖 **API reference**: [`operations::lists::pop`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.pop.html) | [`operations::lists::remove_by_value`](https://docs.rs/aerospike/latest/aerospike/operations/lists/fn.remove_by_value.html) | [`ListReturnType`](https://docs.rs/aerospike/latest/aerospike/operations/lists/struct.ListReturnType.html)

For map-bin equivalents (`operations::maps`) and nested-path navigation with `CdtContext`, see the [`operations::maps`](https://docs.rs/aerospike/latest/aerospike/operations/maps/index.html) API reference.