Rust SDK overview
A tour of the CocoIndex Rust SDK — crate layout (core, prelude, connectors, ops, resources), feature flags, common types like StableKey, and its async-only API.
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 fns.
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.
Until the crate is published, depend on it from GitHub, as Installation shows:
[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:
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 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 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]:
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(())
}// 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 and Processing Component.