The Problem: Document Processing for LLMs
Large Language Models excel at understanding text, but they struggle with binary document formats. Before you can feed a Word document, PowerPoint presentation, Excel spreadsheet, or PDF into an LLM pipeline, you need to convert it to clean, structured text. Traditional conversion tools are often slow, produce messy output, or require complex setup with multiple dependencies.
Firecrawl’s anydoc, released August 3, 2026, solves this with a single function call that converts common office formats to clean Markdown in single-digit milliseconds. Built in Rust with Python and Node.js bindings, it’s designed specifically for LLM workflows [S1].
Under the Hood: Rust Powered
anydoc’s core is written in Rust, chosen for its memory safety, speed, and excellent FFI (Foreign Function Interface) capabilities [S1]. The Rust core parses the binary structure of each format and emits a structured intermediate representation (IR). This IR is then rendered to GitHub-flavored Markdown.
For each format, anydoc uses specialized parsers:
- Word (.docx): Uses the zip-based Open XML format, parsing the document.xml and related parts directly.
- Excel (.xlsx): Parses the shared strings table and sheet data with streaming to handle large sheets efficiently.
- PowerPoint (.pptx): Extracts text from shape.xml and preserves slide order and hierarchy.
- PDF: Uses poppler via Rust bindings for text-based PDFs; falls back to Tesseract OCR for scanned documents.
- CSV: Streaming parsing with automatic dialect detection.
The Rust core is exposed to Python via PyO3, creating a Python extension that feels native. Node.js bindings use neon. This means the conversion happens at near-native speed with no Python-level loops over large data structures [S1].
Because the core is Rust, anydoc benefits from zero-cost abstractions and predictable performance. The single-digit millisecond times come from avoiding unnecessary allocations and using memory-mapped file I/O where possible.
How It Works: One Function Call
anydoc is a Rust-powered library that provides bindings for Python, Node.js, and can be used as a CLI tool. The Python interface is particularly simple:
“`python from firecrawl_anydoc import anydoc
Convert any supported format to Markdown
markdown_text = anydoc.convert(“report.docx”) markdown_text = anydoc.convert(“presentation.pptx”) markdown_text = anydoc.convert(“data.xlsx”) markdown_text = anydoc.convert(“document.pdf”) “`
Each conversion takes single-digit milliseconds on modern hardware [S1]. The library preserves document structure where possible — headings become Markdown headers, lists become Markdown lists, tables become Markdown tables — while stripping out unnecessary formatting and binary cruft.
Supported Formats
anydoc handles the most common office and document formats [S1]:
- Word: .doc, .docx
- PowerPoint: .ppt, .pptx
- Excel: .xls, .xlsx
- PDF: .pdf (with OCR fallback for scanned documents)
- OpenDocument: .odt, .ods, .odp
- EPUB: .epub
- CSV: .csv
- RTF: .rtf
The output is clean GitHub-flavored Markdown that LLMs can process efficiently. Tables maintain their structure, lists retain hierarchy, and heading levels are preserved.
Getting Started
Installation
Install the Python package with pip [S1][S2]:
“bash pip install firecrawl-anydoc “
The package includes the Rust binary and Python bindings [S2]. No separate Rust installation is needed [S1].
Basic Usage
“`python from firecrawl_anydoc import anydoc
Simple conversion
markdown = anydoc.convert(“financial_report.xlsx”) print(markdown)
Convert and save to file
with open(“report.md”, “w”) as f: f.write(anydoc.convert(“research_paper.pdf”))
Convert bytes (useful for web applications)
with open(“document.docx”, “rb”) as f: file_bytes = f.read() markdown = anydoc.convert_bytes(file_bytes, “.docx”) “`
Advanced Options
anydoc provides options for fine-tuning the conversion [S1]:
“`python
Preserve comments in Excel files
markdown = anydoc.convert(“spreadsheet.xlsx”, {“preserve_comments”: True})
Extract images as base64
markdown = anydoc.convert(“presentation.pptx”, {“extract_images”: True})
Set OCR language for PDFs
markdown = anydoc.convert(“scanned.pdf”, {“ocr_lang”: “eng+fra”})
Convert specific sheets or slides
markdown = anydoc.convert(“workbook.xlsx”, {“sheet_names”: [“Q1”, “Q2”]}) markdown = anydoc.convert(“deck.pptx”, {“slide_range”: [1, 5]}) “`
Performance and Quality
Speed
Conversions complete in single-digit milliseconds for typical documents [S1]:
- Word documents (10-50 pages): 2-8 ms
- Excel spreadsheets (multiple sheets): 3-10 ms
- PowerPoint presentations: 4-12 ms
- PDFs (text-based): 5-15 ms
- Scanned PDFs (with OCR): 100-500 ms depending on page count
Output Quality
The Markdown output preserves semantic structure:
- Document headings → Markdown headers (#, ##, ###)
- Bullet and numbered lists → Markdown lists (-, 1.)
- Tables → GitHub-flavored Markdown tables
- Code blocks → fenced code blocks with language hints
- Hyperlinks → standard Markdown links
- Emphasis (bold/italic) → bold and italic
Complex elements like SmartArt, equations, and macros are either converted to appropriate Markdown representations or noted in comments.
Real-World Usage Examples
Here are practical examples of how anydoc fits into LLM workflows [S1]:
RAG Pipeline Preprocessing “python def process_uploaded_file(file_path): # Convert to Markdown for embedding markdown = anydoc.convert(file_path) chunks = split_into_chunks(markdown) # Your chunking function embeddings = embed_model.encode(chunks) vector_store.add(embeddings, chunks) return len(chunks) “
Document Q&A Bot When a user uploads a document, convert it immediately: “python @app.route('/upload', methods=['POST']) def upload_document(): file = request.files['doc'] file_bytes = file.read() markdown = anydoc.convert_bytes(file_bytes, file.filename) # Now feed markdown to your LLM for Q&A answer = llm.ask(markdown, user_question) return jsonify({"answer": answer}) “
Knowledge Base Sync Keep your vector store updated with the latest documents: “python def sync_knowledge_base(): for doc_path in scan_directory("/company/docs"): markdown = anydoc.convert(doc_path) update_vector_store(doc_path, markdown) “
These patterns show how anydoc eliminates the document processing bottleneck in LLM applications, making it feasible to process hundreds of documents per second in a production system.
This makes anydoc ideal for high-throughput LLM applications where document processing speed is critical.
Limitations to Know
Limitations to Know
PDF OCR Dependency. For scanned PDFs, anydoc uses Tesseract OCR as a fallback. You need to have Tesseract installed and language data available for OCR to work [S1]. Pure text PDFs convert without external dependencies.
Complex Formatting. Some advanced Word/PowerPoint features like complex animations, macros, or embedded objects may not convert perfectly. The library focuses on preserving content structure over pixel-perfect layout.
File Size Limits. While there’s no hard limit, extremely large files (100MB+) may consume significant memory during conversion. For very large documents, consider splitting them first.
No Format Preservation. The output is Markdown, not a format-specific representation. If you need to round-trip back to the original format, you’ll need different tools.
Verdict and Conclusion
Score: 5/5 — Do Not Miss. For anyone building LLM pipelines that need to process office documents, anydoc is essential. It’s fast (single-digit ms), simple (one function call), high-quality (clean structured Markdown), and broad in format support.
Best for: Developers building LLM applications that need to ingest office documents — RAG pipelines, document summarization tools, knowledge base builders, or any application that lets users upload files for AI processing.
Skip if: You only need to process plain text files, or you require format-preserving conversion back to the original binary format.
Evolve this: Try integrating anydoc into a document upload endpoint for your LLM chatbot, or use it to preprocess your company’s internal wiki exports before feeding them into a retrieval system.
Sources
- [S1] firecrawl/anydoc GitHub repository — GitHub (2026-08-03)
- [S2] firecrawl-anydoc PyPI package — PyPI (2026-08-03)
- [S3] @firecrawl/anydoc npm package — npm (2026-08-03)
