docling-pdf 2.51.3

PDF/image backend for docling.rs: pure-Rust text layer and page renderer + ONNX layout/table/OCR pipeline.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
# docling.rs

<p align="center">
  <img src="https://raw.githubusercontent.com/docling-project/docling.rs/refs/heads/master/docs/assets/logo.svg" alt="docling.rs — a duck feeding a document into a meat grinder" width="240">
</p>

<p align="center">
  <a href="https://github.com/docling-project/docling.rs/actions/workflows/ci.yml"><img src="https://github.com/docling-project/docling.rs/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
  <a href="https://docling-project.github.io/docling.rs/"><img src="https://img.shields.io/badge/demo-live-brightgreen" alt="Live browser demo"></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/github/license/docling-project/docling.rs" alt="License MIT"></a>
  <a href="https://crates.io/crates/docling"><img src="https://img.shields.io/crates/v/docling?logo=rust" alt="crates.io version"></a>
  <a href="https://pypi.org/project/docling-rs/"><img src="https://img.shields.io/pypi/v/docling-rs?logo=pypi&logoColor=fff" alt="PyPI version"></a>
  <a href="https://www.npmjs.com/package/docling.rs"><img src="https://img.shields.io/npm/v/docling.rs?logo=npm&logoColor=fff" alt="npm version"></a>
  <a href="https://github.com/docling-project/docling.rs/releases"><img src="https://img.shields.io/github/v/release/docling-project/docling.rs?label=release&logo=github" alt="GitHub release"></a>
  <a href="https://crates.io/crates/docling"><img src="https://img.shields.io/crates/d/docling?label=crates.io%20downloads" alt="crates.io downloads"></a>
  <a href="https://pepy.tech/projects/docling-rs"><img src="https://static.pepy.tech/badge/docling-rs/month" alt="PyPI downloads/month"></a>
  <a href="https://www.npmjs.com/package/docling.rs"><img src="https://img.shields.io/npm/dm/docling.rs?label=npm%20downloads" alt="npm downloads/month"></a>
</p>

**docling.rs** converts documents — PDF, Office, HTML, scans, audio — into
Markdown, docling JSON and the other shapes an LLM or a RAG pipeline can
read. It is a Rust port of IBM's
[docling](https://github.com/docling-project/docling): the same output,
byte-for-byte, from one static binary. No Python, no PyTorch.

Pulling text out of a PDF is easy. Keeping its *structure* — headings in
order, tables as tables, scanned pages read — takes layout analysis, table
recognition and OCR. docling has the models for that, and a Python stack to
match. docling.rs runs the same models from a single binary: PDF 4.3× faster
than Python docling at under half the RAM, Office and HTML 20–60× faster, and
tables that survive — cell recall 0.94 where MarkItDown gets 0.31
([numbers](#conformance-with-microsoft-markitdown),
[method](./docs/PDF_CONFORMANCE.md#performance--review--profiling-notes)).

**Coming from [MarkItDown](https://github.com/microsoft/markitdown)?**
`pip install docling-rs`, swap one import —
`from docling_rs.markitdown import MarkItDown` — and keep its API, every
format it converts included, with real layout analysis, tables and OCR
behind it: [guide](./docs/MARKITDOWN.md),
[measured side by side](#conformance-with-microsoft-markitdown).

**Coming from [Marker](https://github.com/datalab-to/marker)?**
`pip install docling-rs`, swap the imports —
`from docling_rs.marker.converters.pdf import PdfConverter` — and keep its
API: `create_model_dict`, `text_from_rendered`, the JSON block tree, chunks,
`marker_single`'s CLI and output layout, with docling's layout analysis,
TableFormer and OCR behind it and no PyTorch or inference server:
[guide](./docs/MARKER.md), [measured side by side](#conformance-with-marker).

**Coming from [MinerU](https://github.com/opendatalab/MinerU)?**
`pip install docling-rs`, swap the imports —
`from docling_rs.mineru.parser import parse` — and keep MinerU 4's SDK:
`ParseResult`, `markdown()`, the Middle JSON, Content Lists and Structured
Content, `save()`'s layout and `mineru-kit parse`, with docling's layout
analysis, TableFormer and OCR behind it and no DocVortex or llama.cpp:
[guide](./docs/MINERU.md), [measured side by side](#conformance-with-mineru).


## Install

```bash
# CLI + models (Linux x64/arm64/s390x + macOS arm64 prebuilt; builds from source elsewhere)
curl -fsSL https://raw.githubusercontent.com/docling-project/docling.rs/master/scripts/install/install.sh | bash
docling-rs example.pdf          # Markdown on stdout

# or from crates.io; --cli puts the models where the installed binary looks
cargo install docling-cli
curl -fsSL https://raw.githubusercontent.com/docling-project/docling.rs/master/scripts/install/download_dependencies.sh | sh -s -- --cli

pip install docling-rs          # Python — drop-in for docling's, MarkItDown's, Marker's and MinerU's APIs
npm install docling.rs          # Node.js / Bun
cargo add docling               # Rust library

# containers, models baked in (-cuda variants for NVIDIA)
docker run --rm -v "$PWD:/data" ghcr.io/docling-project/docling-rs paper.pdf
docker run -p 127.0.0.1:5001:5001 ghcr.io/docling-project/docling-rs-serve
```

Office, HTML, Markdown and e-mail need no models. PDF, images and audio need
the ONNX models (layout, OCR, TableFormer, Whisper; under 1 GB): `install.sh`,
`--cli` and the containers bring them along; with `pip`, run
`python -c "import docling_rs; docling_rs.download_models()"` once; with `npm`
or a checkout, run `download_dependencies.sh` where you convert
([details](#getting-the-ml-models)). Windows: [`docs/WINDOWS.md`](./docs/WINDOWS.md).

**▶ [Try it in your browser](https://docling-project.github.io/docling.rs/)**
first — the converter as wasm, OCR included; nothing leaves your device.

## Use

```bash
docling-rs report.pdf > report.md               # Markdown (streamed page by page)
docling-rs report.pdf --to json                 # docling JSON; also html, text, latex, dclx, chunks, images
docling-rs --input ./docs --output ./out        # a directory tree; --jobs N in parallel
docling-rs https://example.com/paper.pdf        # URLs, data: URIs and stdin (`-`) too
docling-rs https://www.youtube.com/watch?v=ID   # a YouTube video: title, description, caption transcript (--to vtt keeps the timing)
docling-rs --help                               # every flag: OCR, page ranges, images, enrichment, redaction …
```

```python
from docling_rs import DocumentConverter       # was: from docling.document_converter import …
doc = DocumentConverter().convert("report.pdf").document
print(doc.export_to_markdown())
```

```js
import { convertFileAsync } from 'docling.rs'
const { content } = await convertFileAsync('report.pdf', { to: 'markdown' })
```

```rust
use docling::{DocumentConverter, SourceDocument};
let result = DocumentConverter::new().convert(SourceDocument::from_file("report.pdf")?)?;
println!("{}", result.document.export_to_markdown());
```

```bash
curl -F file=@report.pdf 'localhost:5001/v1/convert?to=md'   # the server; OpenAPI at /openapi.yaml
```

Same options, same outputs on every surface — every option in
[`docs/OPTIONS.md`](./docs/OPTIONS.md).

## Highlights

- **From Python docling:** `from docling_rs import DocumentConverter`;
  `result.document` is a genuine `DoclingDocument`
  ([migration notes]./crates/docling-py/README.md#migrating-from-python-docling).
- **Every docling format, and a few it lacks** — the table under
  [Status]#status, each validated against live docling
  ([Conformance]#conformance-with-python-docling).
- **Every output docling has:** Markdown (docling's, or a stricter dialect),
  docling JSON, HTML, plain text, DocLang, LaTeX, Pandoc AST (→ DOCX, EPUB,
  Typst… through pandoc), WebVTT subtitles, RAG chunks and page images
  ([output formats]./crates/docling/README.md#output-formats).
- **From any language:** Rust, Python, Node.js / Bun, the browser (wasm,
  fully client-side), C, C++, C#, Go, Java and Swift through one C header,
  any HTTP client, the shell
  ([Integration]#integration--using-doclingrs-from-your-language).
- **A drop-in server for docling-serve:** Open WebUI uses it as its Docling
  content-extraction engine — point *Docling Server URL* at
  `http://<host>:5001` — and n8n, Dify and LangChain clients work unchanged
  ([`docling-rs serve`]#http-conversion-api--docling-rs-serve,
  [Open WebUI setup]./crates/docling-serve/README.md#open-webui).
- **AI agents (MCP):** `docling-rs mcp` gives Claude Desktop, Claude Code,
  Cursor or VS Code MarkItDown's `convert_to_markdown` tool, plus `convert`
  for JSON, chunks and the rest — `uvx docling-rs-mcp`, or
  `claude mcp add docling -- docling-rs mcp` ([MCP server]#mcp-server--docling-rs-mcp).
- **LangChain:** `pip install "docling-rs[langchain]"` — langchain-docling's
  `DoclingLoader` on the Rust engine, one import to swap
  ([details]./crates/docling-py/README.md#langchain).
- **AutoGen:** `pip install "docling-rs[autogen]"` — `DoclingIndexer` fills
  any AutoGen memory with chunks that carry their pages, `DoclingConvertTool`
  lets an agent read documents ([details]./crates/docling-py/README.md#autogen).
- **Your own formats:** register a backend for a format docling.rs does not
  read — or to read one of its formats your way — from Rust, Python
  (`@docling_rs.register_backend(extensions=["rtf2"])`, and MarkItDown's
  `register_converter` and plugins) or Node.js, ahead of the built-in formats
  ([pluggable backends]./crates/docling/README.md#pluggable-backends).
- **RAG:** `docling-rag` — chunk, embed and search with a REST API and a web
  UI ([RAG subsystem]#rag-subsystem).
- **Runs where you are:** Linux x64 / arm64 / s390x, macOS (Apple Silicon)
  and Windows prebuilt (CLI, wheels, npm), Intel macs from source, containers
  for amd64 and arm64; NVIDIA
  CUDA and TensorRT, DirectML (a prebuilt Windows CLI), CoreML and WebGPU in the browser as opt-in
  accelerators ([GPU]./docs/MODELS.md#gpu-execution-providers-optional-off-by-default,
  [IBM Z]./docs/IBMZ.md).

Developed with **Claude Code** and _[TENET](https://github.com/artiz/tenet/tree/master)_ (minimalistic AI-driven development framework).

## Status

Every format in docling's pipeline converts — plus a few docling lacks. A
file with no or an unknown extension, stdin, an upload or a `data:` URL is
typed by its content (`InputFormat::detect`, `docling_rs.detect_format`,
`detectFormat`: the packages, the OLE files, PDF, images, audio and video,
iWork, XML, JSON, notebooks, messages, …), and a file that fails under its
extension is checked by content and converted as what it really is, with a
warning.

| Category | Formats |
|---|---|
| Text & markup | Markdown, AsciiDoc, HTML, MHTML, LaTeX (multi-file arXiv projects, math, tables); plain text and source code (`.py`, `.yaml`, `.log`, … — any text file, as a code block or paragraphs), generic JSON / JSON Lines and XML (kept as code blocks); RSS / Atom / RDF feeds (`.rss`, `.atom`, `.rdf` or a bare `.xml`: the feed's title, each item's heading, date and body); Jupyter notebooks (`.ipynb`: markdown cells, code cells in the kernel's language, outputs on request) |
| Word processing | DOCX, Word 97–2004 `.doc` (and Word 6/95, 1.x/2.0), ODT, OpenOffice / StarWriter, AbiWord, WordPerfect, MS Works, EPUB, RTF |
| Presentations | PPTX, PowerPoint 97–2003, ODP, OpenOffice / StarImpress |
| Spreadsheets | XLSX, XLSB, Excel 97–2004, ODS, CSV / TSV, dBase, DIF, SYLK, Lotus 1-2-3, Quattro Pro, MS Works |
| Diagrams · Apple iWork | Visio, SVG · Pages, Numbers, Keynote |
| PDF & images | PDF (layout, TableFormer, OCR), PNG, JPEG, TIFF, BMP, WebP, GIF, HEIC (opt-in), METS/GBS scans, DjVu |
| XML · docling native | JATS, USPTO, XBRL, DocLang · docling JSON, DocTags, DCLX |
| Email · subtitles · mainframe | `.eml`, Outlook `.msg` · WebVTT · EBCDIC records through a COBOL copybook |
| Audio · video | WAV, MP3, M4A, AAC, OGG, FLAC; MP4, AVI, MOV, MKV, WebM, MPEG — local Whisper or Parakeet, plus scene frames from video; a YouTube watch URL — the video's title, description and caption transcript as timed items (`--asr-lang` picks the language) |

Every extension, with what each backend does:
[`docs/MIGRATION.md`](./docs/MIGRATION.md#every-extension-by-category).

<details>
<summary><b>Installing ffmpeg</b> (optional — only for video frame sampling)</summary>

Any ffmpeg ≥ 4.x on `PATH` works; docling.rs shells out to the binary and
parses its output, so no dev headers/libraries are needed.

- **Debian/Ubuntu**: `sudo apt-get install ffmpeg`
- **Fedora**: `sudo dnf install ffmpeg-free` (or `ffmpeg` from RPM Fusion)
- **Alpine**: `apk add ffmpeg`
- **macOS**: `brew install ffmpeg`
- **Windows**: `winget install ffmpeg` (or `choco install ffmpeg`, or
  `scoop install ffmpeg`). Installing from a downloaded zip
  ([gyan.dev]https://www.gyan.dev/ffmpeg/builds/ /
  [BtbN]https://github.com/BtbN/FFmpeg-Builds/releases) also works — either
  add the extracted `bin\` folder to `PATH`, or skip `PATH` entirely and point
  `DOCLING_FFMPEG` at the exe:
  `set DOCLING_FFMPEG=C:\tools\ffmpeg\bin\ffmpeg.exe`

Check with `ffmpeg -version`. `DOCLING_FFMPEG` overrides the binary used on
any OS; the docling-rs-serve Docker image ships ffmpeg preinstalled.

A trimmed, decode-only build (`--disable-everything --enable-…`) works too
(#853); docling.rs needs only: the `file` protocol; the demuxers of your
containers (`mov` for mp4/mov/m4v, `matroska` for mkv/webm, `avi`, `mpeg`);
the video decoders of your tracks (`h264`, `hevc`, `vp8`, `vp9`, `av1`,
`mpeg4`, `mpeg2video`, …) with their parsers; the filters `select`,
`metadata`, `fps`, `scale`, `showinfo`; the encoders `png` and
`wrapped_avframe`; the muxers `image2` and `null`. No audio component is
used — the transcript is decoded in Rust — and the scene scan maps the
video stream alone. Missing a component, ffmpeg fails the scene scan
(`Encoder not found`, `Invalid argument`) and the video converts as
transcript only; `DOCLING_RS_DEBUG=1` shows the message.
</details>

## Conformance with Microsoft MarkItDown

[MarkItDown](https://github.com/microsoft/markitdown) converts the same kinds
of documents to Markdown for LLMs. Measured side by side — MarkItDown 0.1.8
(`markitdown[all]`) and docling.rs 2.33.0 (release build), 4 vCPU, no GPU —
on this repository's test corpus and on MarkItDown's own OCR test set
([`scripts/conformance/markitdown_compare.py`](./scripts/conformance/markitdown_compare.py)):

| Corpus (files) | MarkItDown, warm | docling.rs, warm | Cold CLI call, MarkItDown / docling.rs | Word F1 | Table-cell recall | Heading recall |
|---|---|---|---|---|---|---|
| DOCX (38) | 4.22 s | **0.44 s** | 1102 / **14** ms | 0.93 / **1.00** | 0.81 / **1.00** | 0.78 / **1.00** |
| PPTX (8) | 0.30 s | **0.02 s** | 974 / **6** ms | 0.81 / **0.97** | 0.62 / **1.00** | 0.86 / **1.00** |
| XLSX (14) | 0.87 s | **0.15 s** | 849 / **7** ms | 0.60 / **0.95** | 0.78 / **0.98** | — ¹ |
| HTML (32) | 0.34 s | **0.05 s** | 900 / **6** ms | 0.98 / **1.00** | 0.89 / **1.00** | 0.96 / **1.00** |
| CSV (9) | 0.04 s | **0.01 s** | 900 / **4** ms | 1.00 / 1.00 | 0.78 / **1.00** | — |
| EPUB (1) | 0.06 s | **0.01 s** | 897 / **10** ms | 0.99 / **1.00** | — | 1.00 / 1.00 |
| PDF (18), full layout + tables + OCR | **7.6 s** | 38.4 s | 984 / **830** ms | 0.63 / **0.997** | 0.31 / **0.94** | 0.00 / **0.91** |
| PDF (18), text layer only (`--text-layer-only`) | 7.6 s | **0.5 s** | — | 0.63 / **0.97** | 0.31 / 0.00 | 0.00 / 0.00 |

Accuracy is scored against Python docling's groundtruth, which favours
docling.rs by construction; the timings do not depend on it. Text drawn into
images (MarkItDown's own OCR test set) reads at 1.00 with docling.rs' local
OCR, against 0.00–0.33 for MarkItDown without an LLM. Method, caveats and the full
OCR comparison: [`docs/MARKITDOWN.md`](./docs/MARKITDOWN.md#how-the-comparison-is-scored).

## Conformance with Marker

[Marker](https://github.com/datalab-to/marker) (datalab's `marker-pdf`)
converts PDFs and, through a PDF render, Office files to Markdown for LLMs
with a layout model and OCR. Measured side by side — Marker 2.0.0
(`marker-pdf[full]`, its CPU default `fast` mode, llama.cpp for its OCR) and
docling.rs 2.46.2 (release build), 4 vCPU, no GPU — on this repository's test corpus
([`scripts/conformance/marker_compare.py`](./scripts/conformance/marker_compare.py)):

| Corpus (files) | Marker, warm | docling.rs, warm | Cold CLI call, Marker / docling.rs | Peak RSS, Marker (client + servers) / docling.rs | Word F1 | Table-cell recall | Heading recall |
|---|---|---|---|---|---|---|---|
| PDF (18), full layout + tables + OCR | 1312 s | **41 s** | 22.0 s / **1.0 s** | 10.5 GB / **3.1 GB** | 0.93 / **0.997** | 0.41 / **0.94** | 0.66 / **0.91** |
| PDF (18), text layer only (`--text-layer-only`) | 1312 s | **0.44 s** | — | — / 79 MB | 0.93 / **0.97** | 0.41 / 0.00 | 0.66 / 0.00 |
| DOCX (38) | 654 s (1 failed) | **0.56 s** | 23.4 s / **15 ms** | 8.6 GB / **41 MB** | 0.89 / **1.00** | 0.57 / **1.00** | 0.73 / **1.00** |
| PPTX (8) | 3.4 s (3 failed) | **0.02 s** | 21.8 s / **9 ms** | 2.6 GB / **20 MB** | 0.49 / **0.97** | 0.41 / **1.00** | 0.43 / **1.00** |
| XLSX (14) | 164 s (2 failed) | **0.24 s** | 22.8 s / **10 ms** | 12.9 GB / **53 MB** | 0.64 / **0.95** | 0.57 / **0.98** | — ¹ |
| HTML (32) | 1514 s | **0.06 s** | 29 min ² / **8 ms** | 8.8 GB / **21 MB** | 0.94 / **1.00** | 0.50 / **1.00** | 0.84 / **1.00** |
| EPUB (1) | 10.5 s | **0.02 s** | 60.7 s / **13 ms** | 6.8 GB / **19 MB** | 0.98 / **1.00** | — | 1.00 / 1.00 |

A failed file scores 0. ¹ Only one XLSX groundtruth carries a heading.
² The median HTML file needs OCR in Marker: a cold call starts its llama.cpp
server and loads the 1.2 GB OCR model first.

Accuracy is scored against Python docling's groundtruth, which favours
docling.rs by construction; the timings and memory do not depend on it.
Marker reads Office files, HTML and EPUB by rendering them to PDF and
running its vision models on the render; on CPU every page its text check
flags goes through a 1.2 GB vision-language OCR model in a llama.cpp server
that `pip install marker-pdf` does not bring (without it 4 PDFs, 9 DOCX, 10
HTML and the EPUB fail outright). Peak RSS counts Marker's client and its
inference servers. Marker's `balanced` mode (its published benchmarks) needs
a GPU. Method, caveats and the API map:
[`docs/MARKER.md`](./docs/MARKER.md#how-the-comparison-is-scored).

## Conformance with MinerU

[MinerU](https://github.com/opendatalab/MinerU) (OpenDataLab) converts PDFs,
images and Office files to Markdown and JSON for LLMs in four tiers — `flash`
(text layer, no models), `basic` (ONNX layout / table / OCR models),
`standard` and `advanced` (a vision-language model through llama.cpp).
Measured side by side — MinerU 4.0.12 and docling.rs 2.46.2 (release build),
4 vCPU, no GPU — on this repository's test corpus
([`scripts/conformance/mineru_compare.py`](./scripts/conformance/mineru_compare.py)):

| Corpus (files) | MinerU `flash`, warm | MinerU `basic`, warm | docling.rs, warm | Cold CLI call, MinerU `flash` / `basic` / docling.rs | Peak RSS, MinerU `flash` / `basic` / docling.rs | Word F1 (`flash` / `basic` / docling.rs) | Table-cell recall | Heading recall |
|---|---|---|---|---|---|---|---|---|
| PDF (18), full layout + tables + OCR | 22.3 s | 123 s (+ 67 s model load) | **44.0 s** | 3.6 s / 6.5 s / **1.2 s** | 1.4 GB / 4.6 GB / 3.1 GB | 0.87 / 0.74 / **0.997** | 0.28 / 0.44 / **0.94** | 0.57 / 0.58 / **0.91** |
| PDF (18), text layer only (`--text-layer-only`) | 22.3 s | — | **0.69 s** | — / — / — | — / — / 80 MB | 0.87 / — / **0.97** | 0.28 / — / 0.00 | 0.57 / — / 0.00 |
| DOCX (38) | 6.36 s | flash only | **0.59 s** | 2355 ms / — / **15 ms** | 179 MB / — / **41 MB** | 0.97 / — / **1.00** | 0.82 / — / **1.00** | 0.96 / — / **1.00** |
| PPTX (8) | 0.21 s (1 failed) | flash only | **0.05 s** | 2199 ms / — / **9 ms** | 122 MB / — / **20 MB** | 0.79 / — / **0.97** | 0.91 / — / **1.00** | 1.00 / — / 1.00 |
| XLSX (14) | 0.68 s | flash only | **0.19 s** | 978 ms / — / **14 ms** | 140 MB / — / **55 MB** | 0.83 / — / **0.95** | 0.77 / — / **0.98** | — ¹ |
| HTML (32) | 0.89 s | flash only | **0.10 s** | 2015 ms / — / **10 ms** | 157 MB / — / **21 MB** | 0.94 / — / **1.00** | 0.81 / — / **1.00** | 0.96 / — / **1.00** |
| EPUB (1) | 0.09 s | flash only | **0.02 s** | 1909 ms / — / **16 ms** | 99 MB / — / **19 MB** | 1.00 / 1.00 | — | 1.00 / 1.00 |

A failed file scores 0. ¹ Only one XLSX groundtruth carries a heading.

Accuracy is scored against Python docling's groundtruth, which favours
docling.rs by construction; the timings and memory do not depend on it.
MinerU parses Office files, HTML and EPUB at `flash` only; `basic` is its
model tier on CPU; its `standard` tier (a 1.2 B vision-language model through llama.cpp) took 138 s for one page on this CPU and is not in the table. Method, caveats and the API map:
[`docs/MINERU.md`](./docs/MINERU.md#how-the-comparison-is-scored).

## Conformance with Python docling

Every declarative format is compared against the live library — Markdown
byte for byte, JSON structurally (every key and value but `origin`/`version`
and re-encoded image bytes). Latest sweep, docling **2.129.0**
(`scripts/conformance/full_conformance.py`; ✅ all = every file matches):

| Format | Files | Markdown | JSON | Format | Files | Markdown | JSON |
|---|---|---|---|---|---|---|---|
| DOCX | 38 | ✅ all | ✅ all | iWork Pages | 1 | ✅ all | ✅ all |
| HTML | 32 | ✅ all | 31 | iWork Keynote | 5 | ✅ all | ✅ all |
| PPTX | 8 | ✅ all | ✅ all | EBCDIC | 3 | ✅ all | ✅ all |
| XLSX | 14 | 13 ² | 13 ² | JATS | 7 | ✅ all | ✅ all |
| ODF | 7 | ✅ all | ✅ all | DocLang | 15 | ✅ all | ✅ all |
| CSV | 9 | ✅ all | 6 | AsciiDoc | 5 | ✅ all | ✅ all |
| Markdown | 11 | ✅ all | 6 | USPTO | 9 | ✅ all | ✅ all |
| DeepSeek-OCR Markdown | 3 | ✅ all | n/a | EPUB | 1 | ✅ all | ✅ all |
| WebVTT | 4 | ✅ all | ✅ all | LaTeX | 8 | ✅ all | 7 ¹ |
| Email (`.eml`) | 2 | ✅ all | ✅ all |  |  |  |  |

¹ `1706.03762`: one `tabular`'s cells carry consistent `row_span`/`col_span` where upstream writes the span into the offsets only; PDF figures carry no image payload (upstream renders them with pypdfium2).

² `xlsx_02_sample_sales_data`: 20 date cells print by docling PR #4628's number-format rules (#634), which the released docling does not apply yet.

The residuals, with the exact files: [`docs/MIGRATION.md`](./docs/MIGRATION.md).
The PDF/image pipeline is pinned by a deterministic snapshot baseline and
scored against docling's groundtruth in
[`docs/PDF_CONFORMANCE.md`](./docs/PDF_CONFORMANCE.md).

## Performance

One fixture per format through published Python docling and the Rust release
binary (`scripts/test/performance.sh`); docling ÷ docling.rs, so bigger means
Rust wins by more.

| File | Size | Peak-memory ratio | CPU ratio | Warm-conversion speedup |
|---|---:|---:|---:|---:|
| `picture_classification.pdf` (PDF) | 208 KB | **6.5× less** | 0.8× | 10.6× |
| `docx_rich_tables_01.docx` (DOCX) | 3.1 MB | **39× less** | 1.2× | 19× |
| `wiki_duck.html` (HTML) | 240 KB | **57× less** | 1.3× | 47× |
| `elife-56337.nxml` (JATS XML) | 180 KB | **59× less** | 1.2× | 10× |
| `xlsx_04_inflated.xlsx` (XLSX) | 168 KB | **51× less** | 0.9× | 18× |
| `powerpoint_with_image.pptx` (PPTX) | 80 KB | **55× less** | 1.2× | 3.1× |
| `wiki.md` (Markdown) | 8 KB | **57× less** | 1.2× | 1.2× |
| `csv-comma.csv` (CSV) | 4 KB | **64× less** | 1.2× | 0.6× † |

† A 4 KB CSV converts in microseconds, so Rust's own process startup dominates
its number; end to end it is 870× faster.

Declarative formats hold a few MB against docling's ~750 MB (it imports torch
even for them) and finish 300–870× sooner end to end; the PDF peaks at
0.37 GB against 2.4 GB and converts 28.5× faster end to end. Where the time
goes, and what was measured not to help:
[`docs/PDF_CONFORMANCE.md`](./docs/PDF_CONFORMANCE.md#where-the-time-goes).

## Integration — using docling.rs from your language

One engine, several front doors, the same options and outputs everywhere.

| You write… | Use | Install |
|---|---|---|
| Rust | the [`docling`]./crates/docling/README.md crate | `cargo add docling` |
| a shell / CI job | the [`docling-rs` CLI]./crates/docling-cli/README.md, batch mode included | release binaries · `cargo install docling-cli` · `ghcr.io/docling-project/docling-rs` |
| anything that speaks HTTP | [`docling-serve`]./crates/docling-serve/README.md, OpenAPI 3.1 | `ghcr.io/docling-project/docling-rs-serve` · `cargo install docling-serve` |
| Node.js / Bun / Electron | [`docling.rs`]./crates/docling-node/README.md, an N-API addon | `npm i docling.rs` (`docling.rs-cuda`) |
| Python | [`docling-rs`]./crates/docling-py/README.md: docling's, MarkItDown's, Marker's and MinerU's APIs | `pip install docling-rs` (`docling-rs-cuda`) |
| LangChain / LlamaIndex | [`DoclingLoader`]./crates/docling-py/README.md#langchain (langchain-docling's API) · [`DoclingReader`]./crates/docling-py/README.md#llamaindex (llama-index-readers-docling's API) | `pip install langchain-docling-rs` · `pip install llama-index-readers-docling-rs` |
| the browser / Tauri / a PWA | [`docling.rs-wasm`]./crates/docling-wasm/README.md, fully client-side | `npm i docling.rs-wasm` |
| C, C++, C#, Go, Java, Swift, Zig | [`docling-ffi`]./crates/docling-ffi/README.md: one `docling.h` | release archives `docling-ffi-<tag>-<target>` |

**Rust** when you're already in Cargo; the **CLI** for scripts and batch jobs;
**serve** when several services share one warm pipeline; **Node / Python**
in-process; **wasm** when the document must not leave the user's machine;
**FFI** for anything that can call C.

## Rust API

```rust
use docling::{DocumentConverter, SourceDocument};

let converter = DocumentConverter::new();
let result = converter.convert(SourceDocument::from_file("input.md")?)?;

println!("{}", result.document.export_to_markdown()); // Markdown
println!("{}", result.document.export_to_json());     // docling DoclingDocument JSON
```

Every conversion knob is one serializable struct, `docling::ConvertOptions`,
filled the same way by every surface ([`docs/OPTIONS.md`](./docs/OPTIONS.md)).
The [library guide](./crates/docling/README.md) covers the output formats,
error handling, chunking, image extraction, streaming, OCR, the PDF switches,
the remote VLM pipeline and registering your own backends (#680).

## HTTP conversion API — `docling-rs serve`

[`docling-serve`](./crates/docling-serve/README.md) exposes the converter over
HTTP with one warm PDF/image pipeline shared across requests (repeat PDFs skip
the model load), streamed Markdown, batches, ZIP inputs, async jobs, an
interactive test form at `GET /` and an OpenAPI 3.1 description at
`GET /openapi.yaml`. It also serves Python docling-serve's routes, so Open
WebUI, n8n, Dify and LangChain clients work unchanged.

```bash
docker run -p 127.0.0.1:5001:5001 ghcr.io/docling-project/docling-rs-serve
curl -F file=@paper.pdf localhost:5001/v1/convert                # Markdown
curl -F file=@report.docx 'localhost:5001/v1/convert?to=json'    # docling JSON
curl -F file=@a.pdf -F file=@b.docx localhost:5001/v1/convert    # a batch
```

Request options, server flags, async jobs, the docling-serve routes and the
Open WebUI setup: [`crates/docling-serve/README.md`](./crates/docling-serve/README.md);
containers and sizing: [`docs/DEPLOYMENT.md`](./docs/DEPLOYMENT.md).

## MCP server — `docling-rs mcp`

`docling-rs mcp` is a [Model Context Protocol](https://modelcontextprotocol.io)
server in the default `docling-rs` binary and image. Agents get MarkItDown's
`convert_to_markdown(uri)` tool — same name and contract, so a
`markitdown-mcp` setup switches by changing the command — plus
`convert(uri, to, options)` and `list_input_formats()`.

```json
{
  "mcpServers": {
    "docling": { "command": "docling-rs", "args": ["mcp", "--root", "/Users/me/Documents"] }
  }
}
```

```bash
claude mcp add docling -- docling-rs mcp --root ~/Documents     # Claude Code
uvx docling-rs-mcp --root ~/Documents                           # the same server from PyPI
```

Local reads stay under `--root`; URLs need `--allow-url-fetch`. Listed in the
[official MCP registry](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.docling-project/docling-rs)
and on [Smithery](https://smithery.ai/servers/artem-kustikov/docling-rs). The PyPI
launcher, Docker, Streamable HTTP (`--http`), the security model and memory
behaviour:
[`crates/docling-cli/README.md`](./crates/docling-cli/README.md#mcp-server--docling-rs-mcp).

## RAG subsystem

[`crates/docling-rag`](./crates/docling-rag/README.md) turns documents into
chunks, embeds them (Ollama, Gemini or a local ONNX model), stores them
(SQLite + sqlite-vec or PostgreSQL + pgvector) and searches them — hybrid,
multi-query and HyDE retrieval, an evaluation harness, a REST API and a
built-in search UI.

## In the browser — `docling-wasm`

The declarative converters and the PDF text layer compile to WebAssembly:
`npm i docling.rs-wasm`, then `convert(bytes, filename, to)` runs **fully
client-side** — no server, a ~3.4 MB gzipped module, optional in-browser OCR.
Details and the demo page: [`crates/docling-wasm`](./crates/docling-wasm/README.md).

## Node.js, Python and C

- **Node.js / Bun** — [`docling.rs`]./crates/docling-node/README.md on npm, a
  prebuilt N-API addon: sync and async conversion, streaming, chunking, ZIP
  batches, a warm `Pipeline`.
- **Python** — [`docling-rs`]./crates/docling-py/README.md on PyPI
  (`docling-rs-cuda` for NVIDIA): docling's `DocumentConverter` with a genuine
  docling-core `DoclingDocument`, MarkItDown's API, and the LangChain and
  AutoGen integrations.
- **C ABI** — [`docling-ffi`]./crates/docling-ffi/README.md: one library and
  one `docling.h` for C, C++, C#/.NET, Go, Java, Swift and Zig, prebuilt in
  every published release.

## Deploy in a container

| Image | What it is |
|---|---|
| [`ghcr.io/docling-project/docling-rs-serve`]https://github.com/docling-project/docling.rs/pkgs/container/docling-rs-serve | the HTTP API, models baked in (`linux/amd64`, `linux/arm64`) |
| [`ghcr.io/docling-project/docling-rs`]https://github.com/docling-project/docling.rs/pkgs/container/docling-rs | the CLI, entrypoint `docling-rs`, working directory `/data` |
| `…-serve-cuda` · `…-rs-cuda` | the same on CUDA 13 + cuDNN 9 (`linux/amd64`) |

Compose files (standalone, Caddy TLS, CUDA), environment variables, sizing
and observability: [`docs/DEPLOYMENT.md`](./docs/DEPLOYMENT.md).

## Getting the ML models

The PDF/image pipeline needs ONNX models — RT-DETR layout, PP-OCR, and
TableFormer — and audio needs Whisper. `download_dependencies.sh` fetches
them from this repository's
[releases](https://github.com/docling-project/docling.rs/releases) into
`./.models`, where every surface looks (`--cli`: beside a cargo-installed
binary instead):

```bash
scripts/install/download_dependencies.sh                       # from a checkout
curl -fsSL https://raw.githubusercontent.com/docling-project/docling.rs/master/scripts/install/download_dependencies.sh | sh         # anywhere
```

Every asset and option (ASR presets, enrichment models, NER for PII
redaction, INT8, fonts), GPU execution providers and the environment
overrides: [`docs/MODELS.md`](./docs/MODELS.md). IBM Z and other targets
without a prebuilt ONNX Runtime: [`docs/IBMZ.md`](./docs/IBMZ.md).

## Contributing

Bug reports and pull requests are welcome — see
[CONTRIBUTING.md](./CONTRIBUTING.md) for the build and test commands, the
conformance workflow, and the conventions a change is expected to follow.

## License

MIT, matching upstream docling.