PDFtoMD
DevelopersPyMuPDF4LLMPythonPDF

PyMuPDF4LLM Tutorial: Convert PDF to Markdown for LLMs in Python

PyMuPDF4LLM is the fastest way to turn a PDF into clean, LLM ready Markdown from Python. A hands on tutorial with install steps, working code, and the tradeoffs versus Marker and MinerU.

8 min readBy Rafael Abellan

If you need to turn a PDF into Markdown from Python and you want it done in milliseconds rather than minutes, PyMuPDF4LLM is usually the first tool to reach for. It is a thin, purpose built layer on top of PyMuPDF (the fast C backed library also known as fitz) that extracts text as clean, GitHub flavored Markdown. No GPU, no model download, no cloud call. Just pip install and one function.

This tutorial walks through installing it, converting your first PDF, extracting tables and images, chunking output per page for retrieval, and wiring it into a LlamaIndex pipeline. Then we get honest about where it wins and where heavier tools like Marker and MinerU pull ahead.

What PyMuPDF4LLM Actually Does

PyMuPDF4LLM reads the text layer that already exists inside a digital PDF and reconstructs its structure as Markdown. It looks at font sizes to infer heading levels, recognizes bullet and numbered lists, detects tables by analyzing the geometry of text spans, and preserves bold and italic runs. The result is standard Markdown that an LLM can parse without wading through layout noise, absolute coordinates, or repeated page furniture.

The key word is text layer. PyMuPDF4LLM is an extraction tool, not an optical character recognition engine. If your PDF is a born digital document (exported from Word, LaTeX, a browser, or a design tool), the text is already inside the file and extraction is nearly instant. If your PDF is a scan or a photo of a page, there is no text layer to read, and you will need OCR first. We cover that distinction in the tradeoffs section.

Installation

You need Python 3.9 or newer. Create a virtual environment so the dependency does not collide with the rest of your system, then install the package:

python -m venv .venv source .venv/bin/activate pip install pymupdf4llm

That single command pulls in PyMuPDF as a dependency, so there is nothing else to set up. On Windows, activate the environment with .venv\Scripts\activate instead. To confirm it imported correctly:

python -c "import pymupdf4llm; print(pymupdf4llm.__doc__[:60])"

Your First Conversion

The whole library is essentially one call. Point to_markdown at a file path and it returns a Markdown string:

import pymupdf4llm md_text = pymupdf4llm.to_markdown("input.pdf") with open("output.md", "w", encoding="utf-8") as f: f.write(md_text) print(md_text[:500])

That is a complete, working script. Run it against a text based PDF and you will get headings marked with #, lists rendered as - and numbered items, tables as pipe delimited Markdown, and paragraphs separated cleanly. A 30 page document typically converts in well under a second because the heavy lifting happens in PyMuPDF native C code.

Converting Only Certain Pages

If you only care about a range of pages, pass a zero based list. This is handy when a report has a long appendix you want to skip:

md_text = pymupdf4llm.to_markdown( "input.pdf", pages=[0, 1, 2, 3, 4], )

Extracting Tables and Images

Tables are where a lot of converters fall apart, and they are exactly the content an LLM most needs to keep intact. PyMuPDF4LLM detects tables automatically and emits them as Markdown tables, so a financial statement or data sheet usually survives the round trip with its columns aligned. If you also want the figures, tell it to write images to disk and drop image references into the Markdown:

md_text = pymupdf4llm.to_markdown( "report.pdf", write_images=True, image_path="images", image_format="png", dpi=150, )

Each extracted image is saved into the images folder and linked from the Markdown with a standard ![...](...) reference. If you would rather keep everything in a single portable file, set embed_images=True and the images are inlined as base64 data URIs instead of separate files.

Skip the setup entirely. Drop a PDF into PDFtoMD and get clean Markdown back in seconds.

Chunking Output for RAG

For retrieval augmented generation you rarely want one giant string. You want structured segments with metadata so you can embed and cite them. Pass page_chunks=True and instead of a single string you get a list of dictionaries, one per page, each carrying the page text plus metadata:

chunks = pymupdf4llm.to_markdown( "handbook.pdf", page_chunks=True, ) for chunk in chunks: page_no = chunk["metadata"]["page"] text = chunk["text"] print(f"Page {page_no}: {len(text)} chars")

Each dictionary includes a metadata block (source file, page number, title, and more), the Markdown text, and details about any tables and images found on that page. That structure maps directly onto the document objects used by vector stores, which is why this mode is the backbone of most ingestion scripts. For a broader look at preparing documents this way, see our guide to building better RAG pipelines with clean Markdown.

Using It with LlamaIndex

PyMuPDF4LLM ships a native LlamaIndex reader, so you do not have to convert the dictionaries into documents by hand. It returns a list of LlamaIndex Document objects ready to index:

import pymupdf4llm reader = pymupdf4llm.LlamaMarkdownReader() docs = reader.load_data("handbook.pdf") # docs is a list of LlamaIndex Document objects print(len(docs), "documents")

From there you feed docs straight into a VectorStoreIndex and query it. If your stack is LangChain rather than LlamaIndex, convert with page_chunks=True and wrap each chunk in a LangChain document yourself. We break both integrations down in the dedicated article on PDF to Markdown for LangChain and LlamaIndex.

Batch Converting a Folder

Because the API is so small, batch processing is a short loop. Here is a script that converts every PDF in a directory and writes matching Markdown files next to them:

from pathlib import Path import pymupdf4llm src = Path("pdfs") out = Path("markdown") out.mkdir(exist_ok=True) for pdf in src.glob("*.pdf"): md = pymupdf4llm.to_markdown(str(pdf)) target = out / (pdf.stem + ".md") target.write_text(md, encoding="utf-8") print("converted", pdf.name)

On a modest laptop this chews through hundreds of documents per minute, which makes PyMuPDF4LLM a strong default for bulk jobs where the source files are clean digital PDFs. For more Python patterns and library comparisons, our overview of how to convert PDF to Markdown in Python covers the wider toolkit.

Where PyMuPDF4LLM Wins

  • Speed: Pure text extraction with no machine learning inference means conversions finish in milliseconds, not seconds or minutes.
  • Zero heavy dependencies: No PyTorch, no model weights to download, no GPU. The install is small and starts instantly.
  • Simple API: One function covers the common case, and a couple of flags cover the rest.
  • Clean structure on digital PDFs: Headings, lists, tables, and inline formatting come through reliably on well made source files.
  • RAG friendly: Built in page chunking and a LlamaIndex reader make ingestion pipelines short.

Where It Falls Short

  • No built in OCR: Scanned pages and image only PDFs have no text layer, so PyMuPDF4LLM returns little or nothing. You need an OCR step first.
  • Complex layouts: Dense multi column academic papers, heavy figure captions, and unusual page designs can produce reading order glitches that ML based tools handle better.
  • Equations: Mathematical notation is not reconstructed into LaTeX, so scientific papers lose their formulas.

PyMuPDF4LLM vs Marker vs MinerU

These three tools are often mentioned together, but they solve different problems. The honest way to choose is to match the tool to your documents.

ToolApproachSpeedBest for
PyMuPDF4LLMText extractionVery fastClean digital PDFs, bulk jobs
MarkerML models plus OCRModerateMixed quality PDFs, better layout fidelity
MinerUML models plus OCRSlowerScientific papers, equations, figures

Marker uses deep learning models to reconstruct layout and can OCR scanned pages, trading raw speed for accuracy on messier files. MinerU goes further for research documents, preserving LaTeX equations, tables, and figures, at the cost of a bigger install and slower runs. If your pipeline is dominated by dense scientific PDFs, read our MinerU tutorial for the details. A pragmatic pattern many teams use: try PyMuPDF4LLM first, and fall back to an ML based converter only for the documents where the fast path produces poor output.

When to Use a Hosted Converter Instead

A local library is the right call when you are inside a Python codebase, processing files in bulk, or handling sensitive documents that cannot leave your infrastructure. But if you just need a clean Markdown file from a one off PDF, or the document is a scan that needs OCR, standing up and tuning a library is overkill. That is where a hosted tool like PDFtoMD fits: upload the PDF, get clean Markdown back in seconds, no environment to manage. The free tier gives you 3 conversions a month with no credit card, which is enough to check whether the output quality suits your workflow before you commit to writing code. You can see the full range of scenarios on our use cases page.

Frequently Asked Questions

Is PyMuPDF4LLM free?

The library is open source and free to install with pip. Note that PyMuPDF, the underlying engine, is distributed under the AGPL license, so if you embed it in a distributed commercial product you should review the licensing terms or contact Artifex about a commercial license.

Does it handle scanned PDFs?

Not on its own. PyMuPDF4LLM reads an existing text layer, and a scan does not have one. You would need to OCR the document first, for example with a dedicated OCR pipeline, and then extract. If your inputs are mostly scans, an ML based tool with built in OCR or a hosted converter will save you a step.

What Python versions are supported?

Python 3.9 and newer. It runs on Windows, macOS, and Linux with no extra system libraries, since PyMuPDF ships prebuilt wheels for the common platforms.

How does it compare to plain PyMuPDF?

Plain PyMuPDF gives you raw text or detailed span data, and you would have to reconstruct Markdown structure yourself. PyMuPDF4LLM adds the heading detection, table formatting, list handling, and chunking logic on top, so you get LLM ready Markdown from a single call.

Can it output one file per page?

Yes. Use page_chunks=True to get a list with one entry per page, then write each entry to its own file. This is the same mode you use to prepare chunks for embedding in a vector store.

The Takeaway

PyMuPDF4LLM is the fastest, lightest way to turn a digital PDF into clean Markdown from Python. For born digital documents and bulk pipelines it is hard to beat: one install, one function, and structure preserving output in milliseconds. Its limits are equally clear. It does not OCR scans, it will not rebuild equations, and very complex layouts can trip its reading order.

Match the tool to the document. Reach for PyMuPDF4LLM as your default fast path, keep an ML based converter like Marker or MinerU in reserve for the hard files, and lean on a hosted converter such as PDFtoMD when you want clean Markdown without writing or maintaining any code at all.

Rafael Abellan

About the author

Rafael Abellan

Founder, PDFtoMD

Rafael Abellan is the founder of Agência Triva and ships independent side projects in parallel. PDFtoMD came out of a personal frustration: he kept burning through Claude AI's token limit by uploading long PDFs, then losing hours waiting for the cap to reset. He built the tool to fix his own workflow, and now uses it every day.

Ready to convert your PDFs to Markdown?

Free account · 3 conversions/month · No credit card required