CocoIndex core concepts

Declare your outputs. CocoIndex applies changes and reuses cached results.

Version
v 1.0.14
Last reviewed
Nov 4, 2026
ExperimentalThe Rust SDK is experimental. It is outside CocoIndex's compatibility promise: any release, including a minor one, may change or remove its API. It is not yet published on crates.io.

Incremental processing

Data and code change over time. Incremental processing reruns affected work and updates targets, such as a search database.

Manual implementations must track changes and preserve intermediate results. They must also manage inserts, updates, deletes, schema changes, and backfills.

State-driven programming

Declare the target state you want from the current source data. CocoIndex computes and applies the changes needed to match it.

TargetState = Transform(SourceState)

The target state is a pure function of the source state, with no other side effects. Transformations read sources and produce target data, such as database rows or files.

Compare familiar programming models
  • React: Declare UI from state. React updates the UI when state changes.
  • Spreadsheets: Declare formulas. Upstream changes recompute dependent cells.
  • Materialized views: Declare a query. Source changes refresh the view.

App

An app is CocoIndex’s top-level executable. It reads sources, transforms data, and declares target states. CocoIndex synchronizes those target states with external systems, such as Postgres or a vector database.

CocoIndex AppAn App reads state from a source, transforms it, declares target state, and syncs to the target system.
Source System
CocoIndex App
State
Transform F(x)
Target State
Target System
Scroll horizontally to explore the diagram. Use arrow keys when focused.

For example, here’s an app that reads PDFs from a drive, converts them to markdown, and outputs to a folder:

Example App: PDF → MarkdownAn app that reads PDFs from a drive, converts them to markdown, and outputs to a folder.
Drive Folder
CocoIndex App
List of PDFs
Convert all files to Markdown
List of Markdown (filename, content)
Target System
Scroll horizontally to explore the diagram. Use arrow keys when focused.

Processing component

A processing component owns the work and target states for one source item. It runs independently. When it finishes, CocoIndex applies its target states without waiting for other components.

For example, if you have many files in a drive and want to process them file by file, your processing component would operate at the file level:

One processing component per fileEach file gets its own processing component that converts it to markdown.
Drive Folder
CocoIndex App
Drive Folder
a.pdf
Processing Component
Convert to Markdown
a.md
b.pdf
Processing Component
Convert to Markdown
b.md
Scroll horizontally to explore the diagram. Use arrow keys when focused.

One file can produce several target states, such as one embedding vector per text chunk. CocoIndex batches the inserts, updates, and deletes for each file after processing completes. Each target backend applies its batch atomically when supported, such as within a database transaction:

Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
vector1
chunk2
Embed
vector2
b.md
Processing Component
Split into chunks
chunk3
Embed
vector3
chunk4
Embed
vector4
Scroll horizontally to explore the diagram. Use arrow keys when focused.

These examples show how target states change:

Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
vector1
chunk2
Embed
vector2
b.md
Processing Component
Split into chunks
chunk3
Embed
vector3
chunk4
Embed
vector4
c.md
Processing Component
Split into chunks
chunk5
Embed
vector5
chunk6
Embed
vector6
Scroll horizontally to explore the diagram. Use arrow keys when focused.

Adding c.md creates a processing component for it. After processing completes, CocoIndex inserts vector5 and vector6.

Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
vector1
chunk2
Embed
vector2
b.md
Processing Component
Split into chunks
deleted
chunk3
deleted
Embed
deleted
vector3
deleted
chunk4
deleted
Embed
deleted
vector4
chunk5
Embed
vector5
Scroll horizontally to explore the diagram. Use arrow keys when focused.

Updating b.md reduces its content to one chunk. Its target states change from vector3 and vector4 to vector5. CocoIndex deletes the old rows and inserts the new row in one transaction.

Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
vector1
chunk2
Embed
vector2
deleted
b.md
deleted
Processing Component
deleted
Split into chunks
deleted
chunk3
deleted
Embed
deleted
vector3
deleted
chunk4
deleted
Embed
deleted
vector4
Scroll horizontally to explore the diagram. Use arrow keys when focused.

Deleting b.md removes its associated target states, vector3 and vector4, in one transaction.

Function memoization: skip unchanged computations

A memoized function reuses its previous result when its inputs and code remain unchanged. Both processing components and transforms are functions, so you can memoize either level:

  • Processing component: Skip the whole file when its content and processing logic remain unchanged.
  • Transform: Reuse an embedding when its text and embedding logic, including the model, remain unchanged.

See Function Memoization for more details.

Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
memoized
vector1
chunk2
Embed
memoized
vector2
memoized
b.md
Processing Component
Split into chunks
chunk3
Embed
memoized
vector3
chunk4
Embed
memoized
vector4
memoized
Scroll horizontally to explore the diagram. Use arrow keys when focused.

Here’s how memoization behaves in different scenarios:

Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
cache ready — reusedmemoized
vector1
chunk2
Embed
cache ready — reusedmemoized
vector2
cache ready — reusedmemoized
b.md
Processing Component
Split into chunks
chunk3
Embed
cache ready — reusedmemoized
vector3
deleted
chunk4
deleted
Embed
deleted
vector4
chunk5
Embed
memoized
vector5
refreshing — re-executingmemoized
Scroll horizontally to explore the diagram. Use arrow keys when focused.

When b.md changes:

  • a.md and its processing component remain cached.
  • b.md runs again and produces chunk3 and chunk5.
  • Embed(chunk3) reuses its cached result. Embed(chunk5) requires a new computation.
Processing component with chunksEach file is split into chunks; the processing component produces one target state per chunk and syncs them as a unit.
Drive Folder
CocoIndex App
Vector Database
a.md
Processing Component
Split into chunks
chunk1
Embed
cache ready — reusedmemoized
vector1
chunk2
Embed
cache ready — reusedmemoized
vector2
refreshing — re-executingmemoized
b.md
Processing Component
Split into chunks
deleted
chunk3
deleted
Embed
deleted
vector3
deleted
chunk4
deleted
Embed
deleted
vector4
chunk5
Embed
memoized
vector5
chunk6
Embed
memoized
vector6
refreshing — re-executingmemoized
Scroll horizontally to explore the diagram. Use arrow keys when focused.

When the “Split into chunks” logic changes:

  • Both processing components run again.
  • a.md produces the same chunks, so its Embed results are reused.
  • b.md produces chunk5 and chunk6, which require new Embed computations.

A code change can still reuse downstream results when their inputs and function logic remain unchanged.

Try incremental processing

Edit a file and compare the updated row with the cached work. This example uses simulated data.

Loading the playground…

Next steps

Use the Programming Guide to apply these concepts in code:

  • App — creating and running pipelines
  • Target State — declaring what should exist in external systems
  • Processing Component — structuring work and mounting components
  • Function — the #[cocoindex::function] attribute, memoization, and change detection