CocoIndex quickstart

Build your first CocoIndex pipeline in 5 minutes: convert PDFs to Markdown and watch incremental processing only reprocess files that actually changed.

Version
v 1.0.2
Last reviewed
May 2, 2026

In this tutorial, we’ll build a simple app that converts PDF files to Markdown and saves them to a local directory.

Overview

Example App: PDF → Markdown An 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
  1. Read PDF files from a local directory
  2. Convert each file to Markdown using Docling
  3. Save the Markdown files to an output directory (as target states)

You declare the transformation logic with native Python without worrying about changes.

Think: target_state = transformation(source_state)

When your source data is updated, or your processing logic is changed (for example, switching parsers or tweaking conversion settings), CocoIndex performs smart incremental processing that only reprocesses the minimum. And it keeps your Markdown files always up to date.

Setup

  1. Install CocoIndex (see Installation for other package managers) and the Docling dependency:

    bash
    pip install -U cocoindex docling
  2. Create a new directory for your project:

    bash
    mkdir cocoindex-quickstart
    cd cocoindex-quickstart
  3. Create a pdf_files/ directory and add your PDF files:

    bash
    mkdir pdf_files

    You can download sample PDF files from the git repo.

  4. Create a .env file to configure the database path:

    bash
    echo "COCOINDEX_DB=./cocoindex.db" > .env

Define the app

Create a new file main.py. We’ll define the processing functions first, then wire them into an App.

Define file processing

One processing component per file Each 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

This function converts a single PDF to Markdown:

main.py
import pathlib

import cocoindex as coco
from cocoindex.connectors import localfs
from cocoindex.resources.file import PatternFilePathMatcher
from docling.document_converter import DocumentConverter

_converter = DocumentConverter()

@coco.fn(memo=True)
def process_file(
    file: localfs.File,
    outdir: pathlib.Path,
) -> None:
    markdown = _converter.convert(
        file.file_path.resolve()
    ).document.export_to_markdown()
    outname = file.file_path.path.stem + ".md"
    localfs.declare_file(outdir / outname, markdown, create_parent_dirs=True)
  • localfs.File — A file object returned by localfs.walk_dir(), implementing the FileLike base class. See the localfs connector for full details.
  • memo=True — Caches results; unchanged files are skipped on re-runs
  • localfs.declare_file() — Declares a file target state; auto-deleted if source is removed. See localfs as target for the full API.

Define the main function

One processing component per file Each 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
main.py
@coco.fn
async def app_main(sourcedir: pathlib.Path, outdir: pathlib.Path) -> None:
    files = localfs.walk_dir(
        sourcedir,
        recursive=True,
        path_matcher=PatternFilePathMatcher(included_patterns=["**/*.pdf"]),
    )
    await coco.mount_each(process_file, files.items(), outdir)

mount_each() mounts one processing component per file. Each item from files.items() is a (key, file) pair — the key (the file’s relative path) becomes the component subpath automatically.

It’s up to you to pick the process granularity — it can be at directory level, at file level, or at page level. In this example, because we want to independently convert each file to Markdown, the file level is the most natural choice.

Create the App

App definition An App binds source → transform → target state into a single runnable unit.
Source System
CocoIndex App
State
Transform F(x)
Target State
Target System
main.py
app = coco.App(
    "PdfToMarkdown",
    app_main,
    sourcedir=pathlib.Path("./pdf_files"),
    outdir=pathlib.Path("./out"),
)

This defines a CocoIndex App — the top-level runnable unit in CocoIndex. It binds the main function with its arguments.

Run the pipeline

Run the pipeline:

bash
cocoindex update main.py

CocoIndex will:

  1. Create the out/ directory
  2. Convert each PDF in pdf_files/ to Markdown in out/

Check the output:

bash
ls out/
# example.md (one .md file for each input PDF)

Incremental updates

The power of CocoIndex is incremental processing. Try these:

Add a new file:

Add a new PDF to pdf_files/, then run:

bash
cocoindex update main.py

Only the new file is processed.

Modify a file:

Replace a PDF in pdf_files/ with an updated version, then run:

bash
cocoindex update main.py

Only the changed file is reprocessed.

Delete a file:

bash
rm pdf_files/example.pdf
cocoindex update main.py

The corresponding Markdown file is automatically removed.

Next steps

  • Read Core Concepts to understand the mental model — state-driven programming, processing components, and memoization
  • Dive into the Programming Guide, starting with Apps, to learn how to build more complex pipelines
  • Browse more examples for real-world patterns (text embedding, RAG, knowledge graphs)
CocoIndex Docs Edit this page Report issue