In our tests PyMuPDF4LLM converted a 60-page report about 17 times faster than Docling and got every table in a two-column research paper right, including one that Docling misaligned. Docling gave the better result on the tax form, combined the dense table’s year and quarter headers correctly, and read a scanned page without extra installs. PyMuPDF4LLM returned an empty string for that scan until we installed an OCR engine. Both scored 20 of 22 rows on the dense table. Docling is MIT-licensed. PyMuPDF4LLM is AGPL-3.0, or a commercial license from Artifex.
We ran Docling 2.140.0 with default settings and PyMuPDF4LLM 2.0, released on October 19, 2026, on the same five PDFs on one Mac. Since version 2.0 the PyMuPDF4LLM code ships inside the PyMuPDF package, which changes how you install it (see below). Our tested roundup of PDF to Markdown converters ran PyMuPDF4LLM 1.28.2; this post retests the current release, with and without OCR. Disclosure: Parsebridge, which publishes this blog, sells a hosted Docling API.
Docling vs PyMuPDF4LLM at a glance
| Docling | PyMuPDF4LLM | |
|---|---|---|
| Maintainer | Started at IBM Research, hosted by the LF AI & Data Foundation | Artifex Software, the company behind MuPDF and PyMuPDF |
| License | MIT | AGPL-3.0 or Artifex commercial license |
| Install | pip install docling | pip install pymupdf (2.0 and later) |
| Python | 3.10 or newer | 3.11 to 3.15 (PyMuPDF 2.0) |
| How it reads a PDF | Layout model, TableFormer table model and OCR, on PyTorch | MuPDF text extraction plus a small graph neural network for layout, on ONNX Runtime, no GPU needed |
| Install, measured | 1.4 GB environment plus 0.5 GB of models | 262 MB, models included |
| Cold start, measured | 8.7 s | 0.6 s, or 0.9 s with RapidOCR |
| 60-page report, measured | 229 to 231 s | 13 s, or 23 to 24 s with RapidOCR |
| Tables | Markdown tables rebuilt cell by cell | Markdown tables; HTML tables with table_output="html" |
| Multi-column pages | Read in column order | Read in column order, one section out of place on our test paper |
| OCR for scanned PDFs | Built in, on by default | Automatic per page, but only once you install RapidOCR or Tesseract language data |
| Input formats | PDF, DOCX, PPTX, XLSX, HTML, images, audio, LaTeX, email and more | PDF, XPS, EPUB, MOBI, FB2, CBZ, SVG, TXT, Markdown and images; Office files with the paid PyMuPDF Office add-on |
| Output | Markdown, HTML, lossless JSON, DocTags, chunks and more | Markdown, JSON, plain text and layout-based chunks |
Installing PyMuPDF4LLM 2.0
PyMuPDF 2.0 moved the code of two former add-on packages, pymupdf4llm and pymupdf-layout, into the pymupdf package. On PyPI, pymupdf4llm 2.0 is now an empty placeholder with no dependencies. When we ran pip install pymupdf4llm in a fresh environment on October 20, 2026, pip installed only that placeholder, and import pymupdf4llm failed with ModuleNotFoundError.
Install pymupdf instead. It pulls in both placeholders, so the old import pymupdf4llm still works, but the PyMuPDF4LLM API docs now “strongly advise using the Document class”:
pip install pymupdf
import pymupdf
markdown = pymupdf.open("report.pdf").to_markdown()
doc.to_markdown() calls the same function as pymupdf4llm.to_markdown(), and the two gave byte-identical output on all five test files. The layout model is part of the wheel, so nothing is downloaded on first use.
How we tested
We used the five PDFs from the roundup, each stressing one thing:
- Paper: PubTables-1M, a 10-page, two-column research paper with four tables (CC BY 4.0).
- Table: Table 1 from page 31 of the EIA Short-Term Energy Outlook, October 2026, with 15 numeric columns under year and quarter headers (US government work, public domain).
- Scan: our scanned order fixture, an image-only page with a small table.
- Form: page 1 of the 2026 IRS Form W-4 (public domain).
- Report: the full 60-page EIA Short-Term Energy Outlook, for timing.
The machine was a Mac mini with an Apple M4 and 16 GB RAM, on macOS 26.6 and Python 3.12.15. Each tool had its own virtual environment. Docling ran as DocumentConverter() with no options; it picked RapidOCR on PyTorch for OCR and ran its models on the Apple GPU. PyMuPDF4LLM ran as pymupdf.open(path).to_markdown() with no options, which uses its layout model by default. We ran it twice: once as pip install pymupdf installs it, with no OCR engine, and once in a second environment with pip install rapidocr added. PyMuPDF4LLM’s code picks that package first when it is installed.
Each document was converted twice in one process, and we report the second run. “Cold” is a fresh process converting the one-page table PDF, including imports and model loading, with models already downloaded. We started each timed pass only when the one-minute load average was below 3; during the passes it stayed under 4.3, partly from other processes on the machine. Every quality judgment below comes from reading the saved output against the PDF page. Snippets are verbatim; long rows are cut after a few columns and padding spaces are collapsed.
| Seconds | Cold | Paper (10 p.) | Table (1 p.) | Scan (1 p.) | Form (1 p.) | Report (60 p.) |
|---|---|---|---|---|---|---|
| Docling | 8.7 | 7.1 | 4.4 | 3.7 | 3.9 | 229.4 |
| PyMuPDF4LLM | 0.6 | 1.4 | 0.3 | 0.2 (no text) | 0.4 | 13.1 |
| PyMuPDF4LLM with RapidOCR | 0.9 | 4.8 | 0.3 | 0.9 | 0.4 | 23.6 |
Results on the same PDFs
Dense table
Both tools returned a 15-column Markdown table with every two-line row label kept with its values, and both got 20 of the 22 data rows exactly right. The two rows they missed are the last two, heating and cooling degree-days, and they missed them in different ways.
Docling combined the year and quarter headers into one row, then merged the two degree-day rows into one, with two numbers per cell:
| | 2025 - Q1 | 2025 - Q2 | 2025 - Q3 | ...
| U.S. Heating Degree-Days ................... U.S. Cooling Degree-Days .................... | 2,104 53 | 436 464 | 55 902 | ...
PyMuPDF4LLM kept the two rows apart, but the thousands separators of the heating row ended up in the cooling row. It also split the year labels across the quarter columns, so “2025” became 202 and 5:
||**Q1**|**Q2**<br>**202**|**Q3**<br>**5**|**Q4**|...
|US Heating Degree-Days|2104|436|55|1429|...
|.. ...................<br>U.S. CoolingDegree-Days ....................|,<br>53|464|902|,<br>120|...
PyMuPDF4LLM also cut the last letter of one row label (Crude Oil West Texas Intermediate Spo) and put “Real Gross Domestic Product” in an empty row above its values. Docling kept both labels whole.
Two-column paper
Both tools followed the two columns and turned the section titles into headings. PyMuPDF4LLM wraps each heading in bold (## **1. Introduction**), left page numbers in the text as stray lines, and on the last page put section 9.3 before 9.2, the same reading-order slip the roundup found in 1.28.2.
PyMuPDF4LLM got the tables right. Tables 1, 3 and 4 came out cell for cell. Table 2 had all its values in place, but its two-line header cells were split across two rows and the word “oversegmented” across two cells (oversegment and ed PRH). Table 3 is where Docling went wrong. It shifted the last column and merged the two TSR + FA rows:
| TD | Faster R-CNN | 0.825 | 0.985 | 0.927 | 0.866 0.981 |
| | DETR | 0.966 | 0.995 | 0.988 | 0.762 |
| TSR + FA | Faster R-CNN DETR | 0.722 0.912 | 0.815 0.971 | 0.785 0.948 | 0.942 |
PyMuPDF4LLM’s version of the same table:
|TD|Faster R-CNN|0.825|0.985|0.927|0.866|
||DETR|**0.966**|**0.995**|**0.988**|**0.981**|
|TSR + FA|Faster R-CNN|0.722|0.815|0.785|0.762|
||DETR|**0.912**|**0.971**|**0.948**|**0.942**|
Docling got Tables 1 and 4 cell for cell and moved part of one header cell in Table 2. For figures, Docling leaves an <!-- image --> placeholder. PyMuPDF4LLM writes the text it finds inside a figure between <!-- Start of picture text --> comments.
Scanned page
As installed by pip install pymupdf, PyMuPDF4LLM returned an empty string for the scanned page and printed “Warning: RapidOCR is missing. Install for much improved OCR results.” PyMuPDF contains the Tesseract engine, but it needs Tesseract’s language data, which we did not install.
After pip install rapidocr, it ran OCR on the page automatically and returned all of the text and a correct table, with “Total: CHF 42.00” on one line and the three address lines kept apart:
|Item|Quantity|Amount|
|---|---|---|
|Archive folders|3|CHF 18.00|
|Storage boxes|2|CHF 24.00|
Total: CHF 42.00
The package name matters. With the older rapidocr_onnxruntime package, which the roundup used, PyMuPDF4LLM 2.0 ran words together on the same page (SyntheticOCRtestfixture-norealcustomerdata), as the roundup found for 1.28.2. With rapidocr 3.10 the spaces were right.
Docling ran OCR with no extra install and returned the same table, but split “Total:” and “CHF 42.00” into two paragraphs and joined the three address lines into one.
Form
Docling returned the whole W-4 body with step headings and the checkboxes as - [ ] items. It put the Step 3 and Step 4 headings next to each other, placed the “Exempt from withholding” label inside Step 4, moved the Social Security number box to the end and left out the page footer.
PyMuPDF4LLM turned the whole page into a two-column Markdown table and kept the title and footer. The side column was cut at the cell boundary, so words were split across cells (Department of the Tr and easury), and in a few places letters were missing:
|**Enter**|Address<br>**D th th**|
|**Personal**<br>|<br>**oes your name mac e**<br>**name on your social security**<br>**d?**If t t t|
It had no checkbox markup, and dot leaders came out as one . per line. PyMuPDF4LLM 1.28.2 read “Does your name match the” correctly in a side run on the same file, so this part of the form came out worse in 2.0.
Speed and footprint
On the 60-page report PyMuPDF4LLM took 13 seconds, between four and five pages per second, on the CPU. Docling took 229 seconds, just under four seconds per page. Docling’s default OCR also runs on bitmap regions such as the report’s charts. With OCR turned off (PdfPipelineOptions(do_ocr=False)) the same report took Docling 193 seconds.
With RapidOCR installed, PyMuPDF4LLM ran OCR on 4 of the paper’s 10 pages and 13 of the report’s 60, and added the text it read inside charts and figures to the output. That raised its time on the paper from 1.4 to 4.8 seconds and on the report from 13 to 24 seconds. The table and the form came out the same with or without OCR.
A fresh PyMuPDF4LLM process converted the one-page table in 0.6 seconds, including imports and loading its layout model. A fresh Docling process needed 8.7 seconds, about 4 seconds more than a warm conversion of the same page.
The PyMuPDF environment was 262 MB after pip install pymupdf, including ONNX Runtime and NumPy, with the layout model inside the wheel. Adding rapidocr brought it to about 440 MB. The Docling environment was 1.4 GB, including PyTorch, plus 0.5 GB of layout and table models downloaded on first use.
Chunks for RAG
PyMuPDF 2.0 adds doc.to_chunks(), which the PyMuPDF RAG guide presents next to to_markdown(). With defaults it split our paper into 47 chunks with a median of about 1,100 characters, kept each of the four tables whole in one chunk, and attached page numbers, bounding boxes and the section path to each chunk. It took 1.7 seconds. Docling has its own chunkers in docling-core, which we did not test here.
Code for both
Docling:
pip install docling
docling convert report.pdf --to md --output out/
from docling.document_converter import DocumentConverter
converter = DocumentConverter() # reuse it; model loading is the slow part
markdown = converter.convert("report.pdf").document.export_to_markdown()
PyMuPDF4LLM:
pip install pymupdf
pip install rapidocr # only if some of your PDFs are scans
import pymupdf
doc = pymupdf.open("report.pdf")
markdown = doc.to_markdown()
chunks = doc.to_chunks() # layout-based chunks for retrieval
Which to pick
Pick PyMuPDF4LLM when you convert born-digital PDFs at volume on CPUs, when a small install matters, and when the AGPL or a commercial license from Artifex works for you. Our PyMuPDF license explainer covers what Artifex says about SaaS and internal use. It was the faster tool on every file and the more accurate one on the paper’s tables. Install rapidocr if any of your PDFs are scans, and list pymupdf rather than pymupdf4llm in your requirements.
Pick Docling when your PDFs mix born-digital and scanned pages, when forms and multi-level table headers matter, or when you need the MIT license. Plan for about four seconds per page on long documents on a machine like this. Our Docling OCR guide covers how its OCR defaults work and how to turn OCR off for born-digital files.
Both tools made mistakes on these five PDFs, in different places. Run your own worst three or four pages through both before choosing.
Parsebridge
Parsebridge is a hosted Docling API. You send a PDF and get Markdown back without running Docling yourself. It runs Docling 2.124 inside docling-serve 1.32.0, with TableFormer in accurate mode, and turns OCR on when it detects scanned pages. It accepts PDFs only, up to 50 MB. New accounts get 50 free pages once, and plans are $17 a month for 5,000 pages, $79 for 60,000 and $259 for 300,000. Parsebridge does not run PyMuPDF4LLM.
To see Docling’s output on one of your own PDFs first, the free PDF to Markdown converter converts the first page of a PDF up to 10 MB without an account, five times per hour.