Independent guide — not affiliated with IBM or the Docling project. Every command verified on Docling 2.148.0.
  1. Home
  2. RAG & chunking
RAG guide

Docling for RAG — chunks that respect the document

Docling's advantage for RAG is structure: it knows where sections, tables and lists begin and end. Its chunkers use that structure — but the default settings can still produce chunks your embedding model silently truncates. We measured it.

Verified on Docling 2.148.0Updated 27 Oct 2026Includes our own measurements11 min read
In short
  • Use HybridChunker: it splits by document structure, then enforces a token limit and merges small neighbours.
  • Match max_tokens to your embedding model. On our test paper, HierarchicalChunker produced a 1,102-token chunk — over 4× the 256-token limit of all-MiniLM-L6-v2.
  • Embed chunker.contextualize(chunk), not chunk.text: it prepends the section headings.
  • LangChain: langchain-docling (add [local] for local conversion) · LlamaIndex: llama-index-readers-docling + llama-index-node-parser-docling · Haystack: docling-haystack.

The 10-line version#

pythonchunk.py
from docling.chunking import HybridChunker
from docling.document_converter import DocumentConverter

doc = DocumentConverter().convert("https://arxiv.org/pdf/2408.09869").document

chunker = HybridChunker(max_tokens=256)          # match your embedding model
for chunk in chunker.chunk(doc):
    text = chunker.contextualize(chunk)          # headings + text: embed this
    pages = {p.page_no for item in chunk.meta.doc_items for p in item.prov}
    print(len(text), chunk.meta.headings, sorted(pages))

Each chunk carries meta.headings (its section path) and meta.doc_items (the source items with page numbers and bounding boxes) — enough to show citations that link back to the exact spot on the page.

See real chunks#

We converted the 9-page Docling technical report and chunked it three ways with docling-core 2.106.0. Browse the actual output: colour marks the element type, the bar shows each chunk's size against the limit, and red means over the limit.

What we measured#

Chunk sizes on a real documentToken counts (all-MiniLM-L6-v2 tokenizer, headings included) for the Docling technical report.
Hierarchical61 chunks · max 1102Hybrid · 256 tokens48 chunks · max 256Hybrid · 512 tokens30 chunks · max 512064128192256320384448512+

Chunked by docling.org with docling-core 2.106.0. The last bin holds everything ≥ 512.

Show data table
Chunk sizes on a real document
TokensHierarchicalHybrid · 256 tokensHybrid · 512 tokens
0–631320
64–12727104
128–19110106
192–2555243
256–319225
320–383003
384–447004
448–511204
512+201
ChunkerChunksAverage tokensLargestOver 256 tokens
HierarchicalChunker611441,102 (the reference list)5 of 61 (2 over 512)
HybridChunker, max_tokens=256 (default)48182256none
HybridChunker, max_tokens=5123029051216 of 30 (by design: limit is 512)

How the chunkers differ#

HierarchicalChunker

One chunk per document element (paragraph, list, table), with its heading path attached. No token awareness: a long table or list stays one chunk, however large. Good for inspecting structure, risky for embeddings.

HybridChunker

Starts from the hierarchical chunks, splits any chunk over max_tokens using your tokenizer, then merges undersized neighbours that share headings (merge_peers=True). Tables that must split repeat their header (repeat_table_header=True).

HybridChunker settings

ParameterDefaultMeaning
tokenizerall-MiniLM-L6-v2 tokenizerCounts tokens; use the tokenizer of your embedding model
max_tokensthe tokenizer's own limit (256 here)Hard ceiling per chunk, headings included
merge_peersTrueMerge small sibling chunks with the same headings
repeat_table_headerTrueRepeat the header row when a table is split
omit_header_on_overflowFalseDrop the heading context if it alone would overflow
always_emit_headingsFalseEmit heading-only chunks for empty sections

Defaults read from the HybridChunker model fields in docling-core 2.106.0.

Use your embedding model's tokenizer

python
from docling.chunking import HybridChunker
from docling_core.transforms.chunker.tokenizer.huggingface import HuggingFaceTokenizer
from transformers import AutoTokenizer

EMBED_MODEL = "BAAI/bge-small-en-v1.5"           # whatever you embed with
tokenizer = HuggingFaceTokenizer(
    tokenizer=AutoTokenizer.from_pretrained(EMBED_MODEL),
    max_tokens=512,
)
chunker = HybridChunker(tokenizer=tokenizer)

For OpenAI embedding models, docling-core also provides an OpenAITokenizer wrapper around tiktoken (install docling-core[chunking-openai]).

Chunks from the command line#

bash
docling convert report.pdf --to chunks --chunks-max-tokens 512 --output chunks/
docling convert report.pdf --to chunks --chunks-type hierarchical
docling convert report.pdf --to chunks --chunks-tokenizer BAAI/bge-small-en-v1.5

Framework loaders#

LangChain

Since langchain-docling 3.0, the base package is a lightweight client for docling-serve; local conversion needs the local extra.

bash
pip install "langchain-docling[local]"
python
from langchain_docling import DoclingLoader
from langchain_docling.loader import ExportType

loader = DoclingLoader(
    file_path=["https://arxiv.org/pdf/2408.09869"],
    export_type=ExportType.DOC_CHUNKS,           # default; or ExportType.MARKDOWN
)
docs = loader.load()                             # one LangChain Document per chunk
print(docs[0].metadata.keys())

LlamaIndex

bash
pip install llama-index-readers-docling llama-index-node-parser-docling
python
from llama_index.node_parser.docling import DoclingNodeParser
from llama_index.readers.docling import DoclingReader

reader = DoclingReader(export_type=DoclingReader.ExportType.JSON)
docs = reader.load_data(file_path="https://arxiv.org/pdf/2408.09869")
nodes = DoclingNodeParser().get_nodes_from_documents(documents=docs)

Use the JSON export with DoclingNodeParser so nodes keep headings and page provenance in their metadata.

Haystack and others

docling-haystack provides a Haystack converter component. Docling's README also lists Crew AI among its integrations, and docling-mcp exposes conversion as tools for MCP-capable agents.

Practical advice#

  • Store doc_items provenance with each vector so answers can cite page and position.
  • Embed contextualized text, display raw text. Headings help retrieval; users want the passage.
  • Keep the DoclingDocument JSON. Re-chunking with a new tokenizer is instant from JSON, slow from PDF.
  • Check tables. Tables are serialised row by row (“Caption, human human = 84-89. …” in our test). If your answers depend on numbers, test retrieval on table questions specifically.

Frequently asked questions

What is the best Docling chunker for RAG?

HybridChunker in most cases. It starts from the document's structure (like HierarchicalChunker), splits anything over the token limit and merges undersized neighbours with the same headings. On our test paper it kept every chunk within the limit, while HierarchicalChunker produced chunks of up to 1,102 tokens.

What max_tokens should I use with Docling's HybridChunker?

Use the maximum input length of your embedding model, and pass that model's tokenizer. By default HybridChunker uses the sentence-transformers/all-MiniLM-L6-v2 tokenizer and its 256-token limit. For larger models (512 or 8,192 tokens) raise max_tokens accordingly.

What does contextualize() do in Docling?

It returns the chunk text with its heading path prepended (for example '1 Introduction' before the paragraph). Embedding the contextualized text usually improves retrieval because the vector knows which section the text belongs to.

How are tables chunked?

Tables are serialised row by row and kept together where they fit. If a table exceeds the token limit, HybridChunker splits it and, by default, repeats the table header in each piece (repeat_table_header=True).

Can I get chunks from the Docling CLI?

Yes: docling convert file.pdf --to chunks --chunks-max-tokens 512. Use --chunks-type hierarchical for structure-only chunks and --chunks-tokenizer to set the tokenizer.

Sources