Skip to content

MarkItDown vs Docling vs PyMuPDF4LLM: Which Is Best for PDF to Markdown?

The Short Answer

If you need a PDF parser for RAG today, start with PyMuPDF4LLM. It is the best default for most digital PDF-to-RAG workflows: lightweight, designed for fast PDF ingestion, and it emits LLM-shaped Markdown (plus JSON) with layout-aware reading order, table detection, and optional hybrid OCR. When document structure and complex layouts matter — multi-column pages, complex tables, formulas — Docling is the stronger choice, exporting structured JSON with coordinates and Markdown. When simplicity and mixed Office + PDF support matter, MarkItDown is the easiest universal converter. There is no universal winner, but there is a sensible default per document type.

Which One Should I Use?

Your situationPickWhy
Normal digital PDFs, fast RAG ingestionPyMuPDF4LLMLighter-weight, typically faster for native PDF extraction, no ML model downloads; page chunks with metadata suit RAG.
Complex tables, formulas, multi-column layouts, scanned PDFsDoclingDocument-understanding pipeline: layout analysis, reading order, table structure, coordinates, OCR with multiple backends.
Mixed Office (DOCX/XLSX/PPTX) + PDF, simplest universal converterMarkItDownOne tool for many formats with plain LLM-friendly Markdown; optional LLM Vision OCR plugin for scanned content.
OCR-heavy or scanned PDFsDocling OCR or PyMuPDF4LLM hybrid OCRCompare both OCR paths on your files; MarkItDown’s optional OCR plugin is the fallback for mixed-format batches.

The Problem

When I build RAG pipelines, knowledge bases, and agent workflows, the first step is almost always the same: turn PDFs into clean Markdown. But no single parser handles every document well. Marketing pages claim each tool is the best, and searching for “best PDF parser for RAG” or “PDF parser for LLM” returns conflicting advice.

The real question is not “which tool is best” but “which tool is best for this kind of document.” That is why I evaluated MarkItDown, Docling, and PyMuPDF4LLM across common document scenarios based on current capabilities, documentation, and hands-on observations — and why document parsing for RAG usually needs a routing strategy rather than a single tool.

The Three Tools

Tool selection at a glance
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ MarkItDown │ │ Docling │ │ PyMuPDF4LLM │
│ │ │ │ │ │
│ Office + clean PDF │ │ Complex layout │ │ Fast PDF-to-LLM │
│ → plain Markdown │ │ tables + OCR │ │ Markdown + images │
│ │ │ → Markdown + JSON │ │ │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘

MarkItDown is Microsoft’s converter. It handles PDFs, Word, Excel, PowerPoint, HTML, images, and audio. The output is plain Markdown aimed directly at LLM prompts.

Docling is a document-understanding pipeline rather than a PDF-to-Markdown converter. It runs layout analysis, reading-order detection, table-structure recognition, and OCR, and it handles formulas, code, and images. The result is a structured document representation you can export as Markdown, JSON, or plain text — element types and coordinates included.

PyMuPDF4LLM is a PyMuPDF extension purpose-built for LLM ingestion. It turns a PDF into Markdown quickly, with optional image extraction and OCR, and no ML model downloads. Modern PyMuPDF4LLM is more than a lightweight text extractor — details in its section below.

Installation and Minimal Usage

Here are the install commands and the smallest working examples for each tool. I verified these against the official documentation; exact output still depends on your documents.

MarkItDown

Install MarkItDown
pip install markitdown[all]

Convert a file from the command line:

Convert a PDF to Markdown
markitdown path-to-file.pdf -o document.md

Or use the Python API in a script:

markitdown_example.py
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("report.docx")
print(result.text_content)

Core MarkItDown converts native text and embedded text content — it does not OCR scanned pages. OCR ships in the optional markitdown-ocr plugin, which can use LLM Vision to read images inside PDFs as well as inside DOCX, PPTX, and XLSX files. So MarkItDown is weak by default on scanned PDFs, but the plugin turns it into a viable option for OCR-heavy, mixed-format batches.

Docling

Install Docling
pip install docling

The full package pulls ML models for layout, table structure, and OCR on the first run. A slimmer install is available with pip install docling-slim[format-pdf,cli] if you only need PDF and the CLI.

Convert a file from the command line:

Convert a PDF to Markdown
docling report.pdf

The Python API gives more control, including structured JSON export:

docling_example.py
from docling.document_converter import DocumentConverter
converter = DocumentConverter()
result = converter.convert("complex-table.pdf")
print(result.document.export_to_markdown())
# Structured JSON with coordinates for downstream pipelines
doc_dict = result.document.export_to_dict()

Docling’s strongest differentiator is structure: it detects paragraphs, headings, tables, formulas, code blocks, and images on a page and reports their positions, and it supports multiple OCR backends (EasyOCR, Tesseract, and others) for scanned input. The visual below shows what that detection looks like on a real PDF page.

Docling bounding boxes for paragraphs, tables, headings, and images on a PDF page

That coordinate data is what makes Docling a good fit for precise RAG chunking, because a chunk can carry its position and element type as metadata — especially when downstream RAG needs structural metadata rather than flat text. This is also where Docling stands out in the Docling vs PyMuPDF4LLM comparison: both produce Markdown, but Docling keeps the document model behind it.

PyMuPDF4LLM

Install PyMuPDF4LLM
pip install --upgrade pymupdf4llm[ocr,layout]

Convert from the command line, with images written to disk:

Convert a PDF with images
pymupdf4llm document.pdf --out output/ --write-images

Or use the Python API:

pymupdf4llm_example.py
import pymupdf4llm
md = pymupdf4llm.to_markdown(
"research-paper.pdf",
write_images=True,
image_path="./images"
)

The returned string feeds directly into an LLM prompt, a chunker, or a vector store.

Modern PyMuPDF4LLM is more than a simple lightweight Markdown extractor:

  • Layout-aware reading order and multi-column reconstruction via the layout extra.
  • Table detection, so table cells survive as structure instead of raw text runs.
  • Markdown, JSON, or plain-text output — in JSON mode you get page chunks with metadata, including bounding-box/layout information for downstream chunking.
  • Hybrid/selective OCR for scanned or broken regions, rather than an all-or-nothing OCR pass over the whole page.
  • Image extraction with --write-images (CLI) or write_images=True (API).

Its core, open-source focus is PDF; Office support is available through PyMuPDF Pro rather than the free PyMuPDF4LLM path.

Comparing Them Across Common Document Scenarios

I evaluated the three tools across common document scenarios based on current capabilities, official documentation, and hands-on observations — not a formal benchmark. In the MarkItDown vs Docling vs PyMuPDF4LLM decision, real results differ by document, so treat these notes as a starting point for your own tests:

Common document scenarios
1. clean digital PDF
2. multi-column layout
3. simple table
4. complex table
5. equations/formulas
6. embedded images and charts
7. scanned PDF / OCR
8. large PDF

For each tool I checked the same criteria: text extraction quality, reading order, heading preservation, tables, formulas, images, OCR, speed, setup complexity, output readability, RAG suitability, and agent workflow suitability.

The table below is a baseline from official docs and my hands-on notes, not a guarantee. Run the same files through your own pipeline and refine the notes with your numbers.

RequirementMarkItDownDoclingPyMuPDF4LLM
Clean digital PDFStraightforward, LLM-friendly textAccurate text with layout-aware reading orderStrong default; LLM-shaped Markdown
Multi-column layoutContent order can driftLayout analysis reconstructs reading orderLayout mode with reading-order detection
Complex tablesBasic, text-order dependentDedicated table-structure modelTable detection; structure from PDF internals
Equations/formulasLimitedFormula support via layout + structure analysisLimited to what the PDF exposes
Scanned PDF / OCRWeak by default; optional LLM Vision OCR plugin (markitdown-ocr)Multiple OCR backendsHybrid/selective OCR for scanned or broken regions
Reading orderDepends on source orderLayout-model driven, multi-column awareLayout-aware reading order, multi-column reconstruction
Image extractionBasic handlingDetects images and exports with coordinates--write-images / write_images=True
Structured JSON / bounding boxesNoYes — structured doc model with coordinatesYes — JSON mode with page metadata and bounding boxes
Office documentsNative DOCX/XLSX/PPTXDOCX/PPTX supportPDF only (Office via PyMuPDF Pro)
SpeedLightweight, fast text conversionHeavier; ML models add latencyLightweight; typically fast for native PDF extraction
Dependencies/setuppip install markitdown[all]Heavier; downloads ML models on first runpip install pymupdf4llm[ocr,layout]; no ML downloads
RAG chunkingGood text chunks, no structure metadataStrong — element types + coordinatesStrong — page chunks with metadata for RAG
Best use caseMixed Office + PDF, simplicityComplex structure and OCR with metadataDigital PDF → RAG ingestion default

Choose MarkItDown if…

You need mixed Office + PDF ingestion and want the simplest universal converter. MarkItDown natively handles Word, Excel, and PowerPoint, has an easy setup, and emits plain Markdown shaped for LLM prompts. It is the right default when simplicity and one-tool coverage matter more than PDF-specific capabilities. For scanned files it is weak by default — the optional LLM Vision OCR plugin (markitdown-ocr) is the path to OCR, including OCR inside PDF, DOCX, PPTX, and XLSX.

Choose Docling if…

Complex document understanding is the job: multi-column layouts, complex tables, formulas, and scanned pages. Docling is a document-understanding pipeline, not just a converter — layout analysis, reading order, table structure, and coordinates are first-class, and OCR supports multiple backends. If downstream RAG needs structural metadata (element types, bounding boxes) rather than flat text, Docling’s structured JSON is a major reason to pick it.

Choose PyMuPDF4LLM if…

Your pipeline is PDF-only and you want the default parser for normal digital PDFs and fast RAG ingestion. It is lightweight, needs no ML model downloads, and is typically faster for native PDF extraction than ML-based pipelines. Modern PyMuPDF4LLM also handles layout-aware reading order, table detection, JSON output with bounding boxes, page chunks with metadata for RAG, and hybrid OCR for scanned or broken regions — so for OCR-heavy PDFs, compare its OCR path against Docling’s before routing elsewhere.

The Routing Strategy

For production ingestion, I do not pick one parser for everything. I route each document by type:

Decision flow
┌──────────────────────────────┐
│ Incoming document batch │
└──────────────┬───────────────┘
┌──────────────▼───────────────┐
│ Office document? │
└──────────────┬───────────────┘
Yes │ No
┌──────────────▼───────────────┐
│ MarkItDown │
└──────────────────────────────┘
┌──────────────▼───────────────┐
│ PDF: scanned or OCR-heavy? │
└──────────────┬───────────────┘
Yes │ No
┌──────────────▼───────────────┐
│ Docling OCR or │
│ PyMuPDF4LLM hybrid OCR │
└──────────────────────────────┘
┌──────────────▼───────────────┐
│ Complex tables, formulas, │
│ or layout semantics? │
└──────────────┬───────────────┘
Yes │ No
┌──────────────▼───────────────┐
│ Docling │
└──────────────────────────────┘
┌──────────────▼───────────────┐
│ Normal digital PDF → │
│ PyMuPDF4LLM │
└──────────────────────────────┘

Keep MarkItDown as an alternative when simplicity and one-tool mixed-format ingestion matter more than PDF-specific capabilities — for a clean PDF it is a fine choice even though the flow above defaults to PyMuPDF4LLM.

The same idea as pseudo-code:

route_to_parser.py
from pathlib import Path
def route_to_parser(file_path: Path, is_scanned: bool = False) -> str:
ext = file_path.suffix.lower()
if ext in {".docx", ".xlsx", ".pptx"}:
return "markitdown" # Office documents -> MarkItDown
if is_scanned:
return "docling_ocr_or_pymupdf4llm_ocr" # scanned/OCR-heavy PDFs
if needs_complex_structure(file_path):
return "docling" # complex tables/formulas/layout -> Docling
return "pymupdf4llm" # normal digital PDF -> PyMuPDF4LLM

For RAG systems, knowledge bases, and agent workflows, this is the stack I would start with:

  • Default parser for normal digital PDFs: PyMuPDF4LLM for fast RAG ingestion and LLM-shaped Markdown (or JSON metadata when you need page chunks with bounding boxes).
  • Complex documents: Docling with table structure and OCR enabled, exporting both Markdown and structured JSON for chunking and metadata.
  • Office files: MarkItDown, which natively handles Word, Excel, and PowerPoint.
  • Scanned / OCR-heavy PDFs: compare Docling’s OCR (multiple backends) with PyMuPDF4LLM’s hybrid/selective OCR; for mixed-format OCR batches, MarkItDown’s optional LLM Vision OCR plugin is worth testing.
  • Orchestration: a small router that classifies each file and dispatches to the right parser. Cache results and log per-document metrics (timing, token size, extraction quality) to catch regressions.
  • RAG note: prefer structured exports (JSON with coordinates) over raw Markdown when chunking complex tables. Use Markdown for general text chunks. When the choice is PyMuPDF4LLM vs MarkItDown for clean PDFs, it comes down to whether Office support and one-tool simplicity beat PDF-specific output.

Summary

In this post, I evaluated MarkItDown, Docling, and PyMuPDF4LLM for PDF-to-Markdown work in LLM and RAG pipelines: PyMuPDF4LLM as the default for normal digital PDFs and fast RAG ingestion, Docling for complex structure and OCR with structural metadata, and MarkItDown for simplicity and mixed Office + PDF ingestion. No single parser wins every case — in production, route documents by type, cache results, and re-test on your own files before choosing a default parser.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments