Document Pagination#
Docling splits document formats into two categories based on whether they have an intrinsic page structure:
| Category | Formats | Backend type |
|---|---|---|
| Paginated | PDF, PPTX/PPT, XLSX/XLS, images, ODP/ODS | PaginatedDocumentBackend |
| Flow-based | DOCX, HTML, Markdown, AsciiDoc, CSV, LaTeX, EPUB, … | DeclarativeDocumentBackend |
This distinction is declared by every backend via the supports_pagination() classmethod on AbstractDocumentBackend. Paginated backends also inherit from PaginatedDocumentBackend, which requires a page_count() → int method.
Only paginated backends honour the page_range parameter in DocumentConverter.convert(). Flow-based backends receive the entire document in one pass with no page-level filtering.
Backend-by-Backend Behaviour#
Paginated formats#
PDF uses DoclingParseDocumentBackend (and variants), which inherits from PaginatedDocumentBackend. Page filtering is performed by the StandardPdfPipeline via _get_expected_page_nos(), which computes the intersection of the page_range and the document's actual page count.
PPTX — MsPowerpointDocumentBackend inherits from both DeclarativeDocumentBackend and PaginatedDocumentBackend and declares supports_pagination() → True. During __init__, it reads page_range from in_doc.limits and passes start_page/end_page directly to _walk_linear() , which iterates only the requested slides. Each slide's page_no is the 1-based slide index .
XLSX — MsExcelDocumentBackend also declares supports_pagination() → True. It stores page_range at init and in _convert_workbook() skips sheets whose 1-based index falls outside start_page–end_page. Each worksheet maps to one page; page_no tracks position within the (optionally sheet_names-filtered) list of sheets.
Flow-based formats#
DOCX — MsWordDocumentBackend declares supports_pagination() → False. There is no page_range handling and no page_no assigned to content items; Word documents lack a fixed page layout at parse time, so DocItem.prov lists are empty for DOCX content .
HTML — HTMLDocumentBackend extends only DeclarativeDocumentBackend and has no pagination support. It generates ProvenanceItem objects with bounding box data from rendered layout, but page_no has no semantic page meaning in a flow document.
Markdown / AsciiDoc — These backends produce layout-less output with no prov entries on document items at all .
page_range: Pre-Conversion Filtering#
PageRange is an Annotated[Tuple[int, int], AfterValidator] defined in docling/datamodel/settings.py with the constraint start ≥ 1, end ≥ start. The default is (1, sys.maxsize) , meaning all pages are processed unless overridden.
It is stored in DocumentLimits.page_range and flows through:
DocumentConverter.convert(page_range=...) → DocumentLimits → InputDocument.limits → backend
For the paginated PDF pipeline, base_pipeline.py materialises only the pages in range before the batch loop begins :
for i in range(conv_res.input.page_count):
start_page, end_page = conv_res.input.limits.page_range
if (start_page - 1) <= i <= (end_page - 1):
conv_res.pages.append(Page(page_no=i + 1))
For PPTX and XLSX, the page_range check happens inside the backend's own convert() call — slides/sheets outside the range are never parsed. This means page_range is effective for all paginated backends, but is silently ignored by all flow-based (DeclarativeDocumentBackend) backends.
CLI note: There is no
--page-rangeflag for the localdocling convertcommand; it is only available forconvert-remote.
Post-Conversion Page Filtering via Provenance#
Every content node in a DoclingDocument carries a prov: list[ProvenanceItem] field . ProvenanceItem records page_no, bbox, and charspan. Paginated backends populate this for every item they emit; flow-based backends leave it empty or partially populated.
Two APIs use prov for page-scoped access after conversion:
DoclingDocument.filter(page_nrs=...)— returns a newDoclingDocumentcontaining only items whoseprovmatches the requested page set. Use this to produce a standalone document for a page subset (e.g. for export or concatenation).DoclingDocument.iterate_items(page_no=...)— yields(NodeItem, level)pairs whoseprovincludes the given page number, without constructing a new document. Use this for lightweight, read-only per-page traversal.
Because flow-based formats have no prov, both APIs return no items when called with a page_no or page_nrs argument on DOCX/HTML/Markdown output. For paginated formats, page_no values always correspond to slide number (PPTX), sheet position (XLSX), or PDF page number.
For large PDFs, process in page-range chunks and reinstantiate DocumentConverter between batches to release C++ backend memory; use DoclingDocument.concatenate() to merge results .
Key Source References#
| Symbol / File | Purpose |
|---|---|
abstract_backend.py | AbstractDocumentBackend, PaginatedDocumentBackend, DeclarativeDocumentBackend class hierarchy |
settings.py — PageRange, DocumentLimits | page_range type definition and default |
base_pipeline.py L263–266 | Page-range filtering loop in PaginatedPipeline._build_document() |
mspowerpoint_backend.py L141, 209–211 | PPTX reads and applies page_range per slide |
msexcel_backend.py L309, 533–551 | XLSX reads and applies page_range per sheet |
msword_backend.py | DOCX returns supports_pagination() → False; no page tracking |
html_backend.py | HTML is DeclarativeDocumentBackend only; no pagination |
document.py — ProvenanceItem | page_no, bbox, charspan on every content node |
| PDF Page Range Selection KB article | Full usage guide: page_range, filter(), iterate_items() |
| Document Backends KB article | Complete backend inventory and pipeline mapping |