MarkItDown

Converts PDFs, Office documents, images, audio, HTML, and more into clean Markdown built for LLM and RAG pipelines.

Library
PyPI
v0.1.9
191,841 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
88 /100 Excellent
Development Activity 100
Maintenance 100
Community 68
Maturity 44
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
72 /100 Good
Architecture 78
Code Quality 74
Innovation 80
Learning Curve 55

MarkItDown is a Microsoft-maintained Python library that turns a wide range of file formats — PDF, Word, Excel, PowerPoint, images, audio, HTML, CSV/JSON/XML, ZIP archives, EPUBs, and YouTube URLs — into Markdown text that large language models can consume directly. It grew out of the AutoGen project and is designed specifically for the pre-processing step of LLM and retrieval-augmented-generation pipelines, where preserving document structure (headings, lists, tables, links) matters more than pixel-perfect human formatting.

A single MarkItDown class exposes one convert() entry point across every supported format, plus a markitdown CLI for one-off conversions or shell pipelines. Format-specific converters are dispatched through a priority-ordered registry, so specific handlers (docx, pdf, xlsx, Wikipedia, YouTube) run before generic catch-alls. Optional integrations route conversion through Azure Document Intelligence or Azure Content Understanding for higher-fidelity cloud extraction, including structured field extraction serialized as YAML front matter, and a third-party plugin system (discoverable via the #markitdown-plugin GitHub hashtag) lets the community add new converters — including an official markitdown-ocr plugin that adds LLM-vision OCR to image-heavy documents without new binary dependencies.

What You Get

  • A MarkItDown class with one convert() method covering PDF, Word, Excel, PowerPoint, images, audio, HTML, CSV/JSON/XML, ZIP, EPUB, and YouTube URLs
  • A markitdown CLI for converting files from the command line or piping stdin/stdout
  • Priority-ordered converter dispatch via StreamInfo (mimetype/extension/charset), so format-specific converters win over generic text/HTML fallbacks
  • Optional Azure Document Intelligence and Azure Content Understanding backends for cloud-based layout extraction and structured YAML front-matter field extraction
  • A plugin system (enable_plugins=True) that loads third-party converters via importlib.metadata entry points, including the official markitdown-ocr plugin for LLM-vision OCR
  • Granular optional-dependency extras ([pdf], [docx], [pptx], [xlsx], [audio-transcription], [youtube-transcription], etc.) so consumers only install what they need

Common Use Cases

  • Pre-processing arbitrary uploaded documents into Markdown chunks for a RAG ingestion pipeline
  • Feeding PDFs, slide decks, and spreadsheets to an LLM agent as readable, structurally faithful text
  • Batch-converting a document archive (ZIP of mixed file types) into a searchable Markdown corpus
  • Extracting structured fields (invoice totals, contract clauses) from scanned documents via Azure Content Understanding analyzers
  • Building a CLI-driven document-to-Markdown step in a shell script or CI pipeline

Under The Hood

Architecture

MarkItDown centers on a plugin/registry pattern: the MarkItDown class in _markitdown.py maintains a list of ConverterRegistration entries (converter + priority), with PRIORITY_SPECIFIC_FILE_FORMAT handlers (docx, pdf, xlsx, Wikipedia, YouTube) tried before PRIORITY_GENERIC_FILE_FORMAT catch-alls (plain text, generic HTML). Every converter implements the same accepts(file_stream, stream_info) / convert(file_stream, stream_info) contract defined in _base_converter.py, with StreamInfo (mimetype, extension, charset, URL) carrying the routing metadata so accepts() can make a fast determination without fully parsing the file. Third-party converters are loaded lazily and defensively through importlib.metadata.entry_points(group="markitdown.plugin"), with load failures caught and warned rather than crashing the registry — a deliberate isolation boundary between core and community code.

Tech Stack

Built for Python 3.10+ using a Hatchling build backend inside a Hatch-managed monorepo (packages/markitdown, markitdown-mcp, markitdown-ocr, markitdown-sample-plugin). Core runtime dependencies are deliberately minimal: requests for HTTP/URL conversion, beautifulsoup4 and markdownify for HTML-to-Markdown, magika for content-type sniffing, charset-normalizer for encoding detection, and defusedxml for XML parsing hardened against entity-expansion attacks. Everything format-specific — python-pptx, mammoth, pandas/openpyxl/xlrd, pdfminer.six/pdfplumber, olefile, pydub/SpeechRecognition, youtube-transcript-api, and the Azure AI SDKs — lives behind pip extras so installs stay lean. The CLI ships via a project.scripts entry point (markitdown = markitdown.__main__:main).

Code Quality

CI (tests.yml) runs the Hatch test suite across Python 3.10, 3.11, and 3.12 on every pull request, with a dedicated test file per format (test_pdf_masterformat.py, test_pptx_svg.py, test_cu_converter.py, etc.) plus shared fixture vectors in _test_vectors.py and a test_files/ corpus. A pre-commit hook enforces Black formatting, and a separate Hatch environment (tool.hatch.envs.types) wires up mypy, though it is not gated in CI. Errors are surfaced through a custom exception hierarchy (FileConversionException, UnsupportedFormatException, FailedConversionAttempt) rather than swallowed, and the top-level security note in the README explicitly calls out that conversion runs with the calling process’s I/O privileges, directing users toward narrower convert_stream()/convert_local() calls in untrusted contexts.

API Design The public surface is intentionally small: instantiate MarkItDown(enable_plugins=...) once, call .convert(path_or_stream) for any supported format, and read .markdown (or the soft-deprecated .text_content alias) off the result — the same call shape handles a local PDF, a YouTube URL, or a ZIP archive. Cloud backends layer on without changing that shape: passing cu_endpoint or -d/-e flags swaps in Azure Content Understanding or Document Intelligence transparently, and cu_file_types lets callers scope which formats incur billable API calls. The CLI mirrors the Python API 1:1 (markitdown file.pdf -o out.md, stdin piping, --use-plugins, --list-plugins), which keeps the learning curve low for both library consumers and shell users.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers