MarkItDown
Converts PDFs, Office documents, images, audio, HTML, and more into clean Markdown built for LLM and RAG pipelines.
Repository Health
Technical Analysis
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
MarkItDownclass with oneconvert()method covering PDF, Word, Excel, PowerPoint, images, audio, HTML, CSV/JSON/XML, ZIP, EPUB, and YouTube URLs - A
markitdownCLI 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 viaimportlib.metadataentry points, including the officialmarkitdown-ocrplugin 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.