# Rust SDK overview

> **CocoIndex v1, Rust SDK (experimental).** This page documents the CocoIndex **v1** Rust SDK (the `cocoindex` crate). The Rust SDK is experimental: any release may change or remove its API, and it is not yet published on crates.io. The Python SDK pages are at https://cocoindex.io/docs/.
>
> Source: https://cocoindex.io/docs/rust/programming_guide/sdk_overview/ · Rust docs index: https://cocoindex.io/docs/rust/llms.txt · Rust SDK tour: https://github.com/cocoindex-io/cocoindex/blob/main/rust/sdk/SHOWCASE.md · Rust examples: https://github.com/cocoindex-io/cocoindex/tree/main/examples/rust

The CocoIndex Rust SDK is the `cocoindex` crate under `rust/sdk/cocoindex`. Its API is async and runs on Tokio, and your processing functions are `async fn`s.

**Note — Python SDK**
The Rust SDK calls the same core engine as the Python SDK, and the two write one state database format. See the [Python SDK overview](/docs/programming_guide/sdk_overview/).

Until the crate is published, depend on it from GitHub, as [Installation](/docs/rust/getting_started/installation/) shows:

```toml title="Cargo.toml"
[dependencies]
cocoindex = { git = "https://github.com/cocoindex-io/cocoindex", features = [
    "postgres",
    "text",
    "fastembed",
    "fs_live",
] }
```

## Crate organization

| Path | Description |
|------|-------------|
| `cocoindex` | The core API at the crate root: `App`, `Environment`, `Ctx`, `ContextKey`, `Error`, `Result`, the `#[cocoindex::function]`, `#[app]`, `#[lifespan]` and `#[main]` attributes, the `mount!`, `use_mount!` and `mount_each!` macros, `context_key!`, and the `MemoInput` and `SchemaFields` derives. The resource types (`FileEntry`, `DirTarget`, `walk_dir`, `Chunk`, `IdGenerator`, `LiveMap`, `StableKey`, ...) are re-exported here too |
| `cocoindex::prelude` | `use cocoindex::prelude::*;` imports the core API, the resource types, the macros, and `serde::{Serialize, Deserialize}` |
| `cocoindex::connectors::*` | One module per connector, each behind a feature flag of the same name: `postgres`, `sqlite`, `doris`, `lancedb`, `qdrant`, `turbopuffer`, `valkey`, `zvec`, `neo4j`, `falkordb`, `surrealdb`, `bigquery`, `snowflake`, `kafka`, `iggy`, `amazon_s3`, `azure_blob`, `oci_object_storage`, and `gdrive` (feature `google_drive`) |
| `cocoindex::ops::*` | Built-in operations: `text` (feature `text`), `sentence_transformers` and `image` (feature `fastembed`), `api` (feature `embed_api`), `code` (feature `code_match`) |
| `cocoindex::resources::*` | The resource modules behind the root re-exports: `file`, `fs`, `chunk`, `id`, `live_map`, `rate_limit`, `schema`, `view`, `embedder` |
| `cocoindex::inspect` | Reads an app's stored state: stable paths, their details, and tracked target states |

Import connectors and ops by their module; take the rest from the prelude:

```rust
use cocoindex::connectors::postgres;
use cocoindex::ops::sentence_transformers::SentenceTransformerEmbedder;
use cocoindex::ops::text::{RecursiveChunkConfig, RecursiveSplitter};
use cocoindex::prelude::*;
```

## Feature flags

Every connector and op is optional, so a pipeline compiles only the clients it uses. The other features are `fs_live` (live directory watching through `walk_dir(..).live()`), `chrono` and `rust_decimal` (`MemoInput` for those leaf types; a connector feature enables the ones it needs), and `embed_api` (remote embeddings and transcription over an OpenAI-compatible HTTP API). [Installation](/docs/rust/getting_started/installation/#feature-flags) lists them all.

## Common types

### StableKey

`StableKey` is the enum of values that identify a processing component in the component path, and a target state within its target. Its variants are `Null`, `Bool`, `Int`, `Str`, `Bytes`, `Uuid`, `Symbol`, `Array` (a composite key) and `Fingerprint`.

APIs that take a key accept any `IntoStableKey` value: `&str`, `String`, `bool`, the integer types, `uuid::Uuid`, byte strings (`Vec<u8>`, `&[u8]`, `bytes::Bytes`), `()` (for `Null`), or a `StableKey` itself. Common examples include strings (like `"setup"` or `"table"`), integers, and UUIDs. `Symbol` provides predefined names that never conflict with strings (which typically come from runtime data).

Each processing component must be mounted at a unique path. See [Processing Component](/docs/rust/programming_guide/processing_component/) for how the component path tree affects target states and ownership.

## Async only

The Rust API is async and runs on Tokio. There are no sync variants of the orchestration APIs: `ctx.mount`, `ctx.scope`, `ctx.mount_each`, `ctx.map` and the mount macros are all `async`, and a `#[cocoindex::function]` body is an `async fn`. The entry points have `_blocking` forms for code that owns no runtime: `App::open_blocking`, `app.update_blocking`, `app.drop_state_blocking`, `EnvironmentBuilder::build_blocking`. They build a runtime of their own and panic inside one, so use the async forms inside `#[tokio::main]` or `#[cocoindex::main]`:

```rust
use cocoindex::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    let app = App::open("my_app", ".cocoindex_db").await?;
    let stats = app
        .run(|ctx| async move {
            // Declare the desired target state using ctx.
            Ok(())
        })
        .await?;

    println!("{stats}");
    Ok(())
}
```

```rust
// Sync entry point, outside a runtime
let app = App::builder("my_app").db_path(".cocoindex_db").build_blocking()?;
app.update_blocking(|_ctx| async move { Ok(()) })?;
```

Rust has no ambient context: every API takes the component's `Ctx` explicitly, and a processing function takes `&Ctx` as its first argument. See [Function](/docs/rust/programming_guide/function/) and [Processing Component](/docs/rust/programming_guide/processing_component/).
