# TurboVec Index Types Explained: TurboQuantIndex vs IdMapIndex Use Cases

> Explore TurboVec index types: TurboQuantIndex for speed and IdMapIndex for stable IDs. Learn use cases for eager and lazy constructors.

- Repository: [Ryan Codrai/turbovec](https://github.com/RyanCodrai/turbovec)
- Tags: deep-dive
- Published: 2026-08-22

---

**TLDR: TurboVec offers two index types — `TurboQuantIndex` for raw speed with slot-based IDs and `IdMapIndex` for stable external IDs that survive deletions — each with eager or lazy constructors depending on your data pipeline.**

TurboVec is a Rust library for high-performance vector indexing and approximate nearest-neighbor search. As implemented in the [RyanCodrai/turbovec](https://github.com/RyanCodrai/turbovec) repository, it provides two distinct index types, each designed for a specific set of use cases. Understanding these index types in TurboVec is critical for choosing the right structure for your embeddings, whether you're dealing with high-dimensional vectors in production or a simple in-memory search. In this guide, we'll break down both `TurboQuantIndex` and `IdMapIndex`, their construction, and when to use each.

## Overview of TurboVec Index Types

TurboVec's two index families are defined in the source code:

- **`TurboQuantIndex`** — defined in [`turbovec/src/lib.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/src/lib.rs) at line 95. This is the core quantized index that packs vectors into **2–4 bits per coordinate** and uses a blocked layout for SIMD-friendly search.
- **`IdMapIndex`** — re-exported from [`turbovec/src/id_map.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/src/id_map.rs) (the actual struct lives there) and imported in [`lib.rs`](https://github.com/RyanCodrai/turbovec/blob/main/lib.rs) at line 83. It wraps a `TurboQuantIndex` and adds a bidirectional mapping between external 64-bit IDs and internal slot numbers.

Both types support identical search and persistence operations, but they differ fundamentally in how they handle vector identity.

## TurboQuantIndex: Fast Slot-Based Vector Search

### What It Stores

`TurboQuantIndex` stores vectors in a **blocked, packed bit-plane representation** with a configurable bit width (2 to 4 bits per coordinate). The index also maintains a lazily-created SIMD-friendly cache that speeds up repeated searches on the same data.

### Primary Use Case

Use `TurboQuantIndex` when:
- You need **maximum search speed** (both single-threaded and multi-threaded).
- Your vectors are **high-dimensional embeddings** (e.g., 128 to 1536+ dimensions).
- You only require the **slot number** (0-based index) as the identifier for each vector.

This is perfect for feature store lookups where you can keep your own external ID array outside the index and simply translate slot numbers back to your original keys.

### Construction in Code

```rust
use turbovec::TurboQuantIndex;

// Eager construction — you know the dimension up front
let mut idx = TurboQuantIndex::new(1536, 4).expect("construct");

// Add 10 vectors (flat f32 slice)
let vectors = vec![0.0_f32; 1536 * 10];
idx.add(&vectors);

// Search with 2 queries, top-10 results each
let queries = vec![0.0_f32; 1536 * 2];
let results = idx.search(&queries, 10);

// results.indices are slot numbers (0-based)
println!("{:?}", results.indices);

```

The `new(dim, bit_width)` constructor is an eager builder; alternatively, `TurboQuantIndex::new_lazy(bit_width)` defers dimension inference until the first `add` call, which is useful when you don't know the vector size upfront.

## IdMapIndex: Stable External IDs That Survive Updates

### What It Stores

`IdMapIndex` internally wraps a `TurboQuantIndex` but also maintains a **bidirectional map** — a `Vec<u64>` for slot→external ID lookups and a `HashMap<u64, usize>` for external ID→slot lookups. This extra metadata ensures that external identifiers don't change, even when vectors are moved or removed.

### Primary Use Case

Use `IdMapIndex` when you need **persistent identifiers** — e.g., database primary keys, user IDs, or document IDs — that must:
- Remain **stable** across `swap_remove` operations (deletions).
- Be directly returned in search results, so you can immediately know which records are closest.

This index type is ideal for production deployments where you have to delete partial data without invalidating the rest of the index.

### Construction in Code

```rust
use turbovec::{IdMapIndex, IdSearchResults};

// Create an index with stable external IDs (128-dim vectors, 3-bit quant)
let mut idx = IdMapIndex::new(128, 3).expect("Failed to create index");

// Insert a vector with a user-defined ID
let vec = vec![0.5_f32; 128];
let external_id = 42_u64;
idx.add_with_id(&vec, external_id).expect("Failed to add");

// Remove by external ID (slot gets swapped internally, but IDs stay stable)
idx.remove(external_id).expect("Failed to remove");

// Search; results contain the original external IDs
let queries = vec![0.5_f32; 128];
let results: IdSearchResults = idx.search(&queries, 5);
println!("{:?}", results.ids);

```

`IdMapIndex` also offers `new(dim, bit_width)` and `new_lazy(bit_width)` constructors, mirroring the behavior of `TurboQuantIndex`.

## Serialization: Persisting and Loading Indexes

Both index types implement the same `write` and `load` methods, allowing you to persist and restore an index from disk:

```rust
// Save to disk
idx.write("my_index.tv").expect("Failed to write");

// Load later (type is inferred from the file)
let loaded = TurboQuantIndex::load("my_index.tv").expect("Failed to load");

```

The end-to-end example in [`turbovec/tests/write_path.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/tests/write_path.rs) demonstrates creating, writing, loading, and searching both index types, providing a complete reference for persistence.

## Key Source Files in the TurboVec Repository

| File | What You’ll Find |
|------|------------------|
| [`turbovec/src/lib.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/src/lib.rs) | Public API, re-exports, and the core `TurboQuantIndex` definition |
| [`turbovec/src/id_map.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/src/id_map.rs) | Implementation of `IdMapIndex`, the stable-ID mapping logic |
| [`turbovec/tests/write_path.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/tests/write_path.rs) | End-to-end example covering creation, persistence, and search for both index types |
| [`turbovec/tests/id_map.rs`](https://github.com/RyanCodrai/turbovec/blob/main/turbovec/tests/id_map.rs) | Tests validating `IdMapIndex` behavior (addition, deletion, ID stability) |

These files together illustrate the two index families, their construction patterns, and typical workflows.

## Summary

- **`TurboQuantIndex`** is the base index, optimized for speed with slot-based (integer) identifiers. It supports eager (`new`) and lazy (`new_lazy`) construction and is ideal when external IDs are maintained elsewhere.
- **`IdMapIndex`** adds a stable 64-bit external ID layer on top of `TurboQuantIndex`. It allows `add_with_id`, `remove` by external ID, and returns external IDs in search results — perfect for **persistent primary keys** that must survive deletions.
- Both types support `write` and `load` for persistence, and tests in `turbovec/tests` show complete workflows.

Choose **`TurboQuantIndex`** for raw speed and simple slot indexing, or **`IdMapIndex`** for stable external keys in production systems.

## Frequently Asked Questions

### Can you mix `TurboQuantIndex` and `IdMapIndex` in the same application?

Yes, you can. Both index types are independent structs. You might use a `TurboQuantIndex` for rapid throwaway searches and an `IdMapIndex` for persistent storage, as long as you keep the external IDs consistent manually. The source code even re-exports both from [`lib.rs`](https://github.com/RyanCodrai/turbovec/blob/main/lib.rs).

### How do the eager and lazy constructors differ in `TurboVec`?

The eager constructor (`new(dim, bit_width)`) requires you to know the vector dimension upfront, while the lazy `new_lazy(bit_width)` infers the dimension from the first `add` call. Lazy construction is convenient when your data source doesn't expose dimensions early, but it incurs a small first‑call overhead.

### Does `IdMapIndex` support arbitrary external ID types?

The `IdMapIndex` implementation specifically uses `u64` for external IDs (as seen in `add_with_id` and `remove` methods). For string or custom IDs, you would need to map them to `u64` internally before using the index.

### How much memory does `IdMapIndex` add compared to `TurboQuantIndexBow index`?

`IdMapIndex` stores a `Vec<u64>` and a `HashMap<u64, usize>` on top of the quantized vectors. For millions of entries, this adds about 16 bytes per vector for the slot→ID lookup plus extra hash map overhead. This is a reasonable trade‑off when stable IDs are essential.