Skip to content

Choosing a Parser

This guide helps you pick a parser and install the right extra. The default is Docling, the best all-round local choice; the other options trade off file-type coverage, install size, and output quality.

The Parser slot is stage 02 of the pipeline. It turns each file into a normalized ParsedDoc — holding text, structural blocks, tables, and image refs — that every later stage consumes.

indx composes parsers rather than replacing them, so the choice comes down to matching your corpus and constraints to the strengths of each backend.

Every parser implements the same Parser protocol (parse(path) -> ParsedDoc). The pipeline never knows which one is active, so you can switch freely without touching anything downstream.

ParserStrengthsBest forLocal?Extra
Docling (default)High-fidelity layout, reading order, tables, and figures from PDF/Office docs; richest structured output of the local options; permissive (Apache-friendly) license.The default, offline, document-heavy knowledge spaces.Yesindx[docling]
UnstructuredVery broad file-type coverage and a mature partitioning ecosystem.Heterogeneous corpora with many odd/long-tail formats.Yesindx[unstructured]
LlamaParseExcellent on complex/messy PDFs via a hosted service.Hard documents where cloud quality is worth it.No (cloud)indx[llamaparse]
MarkItDownLightweight, fast Markdown conversion with minimal dependencies.Quick/simple conversions and the lightest local install.Yesindx[markitdown]
plaintextZero-dependency fallback that ships in core; reads text as-is.Air-gapped runs, plain-text/Markdown corpora, CI smoke tests.Yesnone (in core)

The parser slot is resolved with the same precedence as every other component:

explicit code argument / use() > CLI flag > indx.toml > documented default

Use --parser to override per run:

Terminal window
# Default (Docling) — requires indx[docling]
indx ./docs --out ./ai-ready
# Lightest local parser
indx ./docs --out ./ai-ready --parser markitdown
# Broad format coverage
indx ./docs --out ./ai-ready --parser unstructured

The parser lives under the [parser] section, keyed engine:

[parser]
engine = "docling" # docling | unstructured | llamaparse | markitdown | plaintext

See the full configuration reference for the complete key table and precedence rules.

For a fully custom or pre-configured parser, pass an instance to the DirectoryPipeline. You can do this at construction or via use():

from indx import DirectoryPipeline
# By name
pipeline = DirectoryPipeline(parser="markitdown")
# By object (anything satisfying the Parser protocol)
from my_pkg import MyMarkdownParser
pipeline = DirectoryPipeline().use(parser=MyMarkdownParser())
space = pipeline.run("./docs", "./ai-ready")

Writing your own parser is covered in Bring-your-own components.

Parsers are optional extras, so the core install stays small. Each backend pulls its own heavy dependencies:

InstallEnables
pip install indx[docling]DoclingParser (default)
pip install indx[unstructured]UnstructuredParser
pip install indx[llamaparse]LlamaParseParser
pip install indx[markitdown]MarkItDownParser
pip install indx[local]The full local profile (docling + ollama + bge-m3 + qdrant), the opt-in offline stack

The plaintext parser needs no extra — it is always available.

indx is designed around four product principles. Each parser trades against them differently.

Docling, Unstructured, MarkItDown, and plaintext all run fully local with no network calls.

LlamaParse is the exception: it is cloud-only. It sends documents to a hosted service and needs an API key, which breaks the local profile. Reach for it only when cloud quality on genuinely hard PDFs is worth crossing that line. See Local & air-gapped.

pip install indx carries no parser beyond the in-core plaintext fallback.

Among the optional parsers, MarkItDown is the lightest, with minimal deps and fast Markdown conversion — the recommended choice when install size matters most. Docling is the heaviest local option, since on some configurations it pulls models and Torch, which is why it ships as an extra rather than in core.

Every parser sits behind the same Parser protocol. A third party can publish a new one, advertised via the indx.parsers entry point, that works by name with no fork of indx.

Swapping parsers is always a config change, never a rewrite. See authoring a plugin.

Chunk, Relate, and Enrich are only as good as the structure the parser preserves.

Docling produces the richest structured output of the local options — reading order, tables, and figures — and generally yields the best chunking and relating. MarkItDown is local and light but loses structure Docling keeps, and plaintext keeps none at all.