Low memory by design
Fetch and retain only the ranges and objects needed for the current page. Cache limits stay fixed even when the source document grows to thousands of pages.
Open-source PDF extraction for JavaScript runtimes
@boxpdf/reader turns PDFs into a structured model and pixel-accurate HTML using only the bytes each page needs. It is fast, bounded-memory, and built for Node, edge functions, and the browser—with no WASM, native binary, or headless browser.
import { httpSource, openPdf } from "@boxpdf/reader";
import { pageToHtml } from "@boxpdf/html-writer";
const pdf = await openPdf(httpSource(url), {
maxBytes: 2 * 1024 * 1024,
maxObjectCacheBytes: 2 * 1024 * 1024
});
const page = await pdf.getPage(0);
viewer.innerHTML = await pageToHtml(page, { profile: "visual" });
Why @boxpdf/reader
Most PDF tools choose between pulling out text and drawing pixels. boxpdf keeps the visual evidence—geometry, fonts, vectors, images, and paint order—while exposing it as a JavaScript model and ordinary HTML.
Fetch and retain only the ranges and objects needed for the current page. Cache limits stay fixed even when the source document grows to thousands of pages.
Pure JavaScript with random-access HTTP, Blob, memory, and custom data sources. No filesystem assumption, WASM module, native addon, or browser process.
Open the cross-reference data and go directly to page one—or page 10,000. Work begins before the entire file has crossed the network.
Visual HTML preserves page coordinates, embedded fonts, images, SVG paths, opacity, rotation, and paint order. PDFium raster fixtures gate the result.
Render the reconstructed HTML in a browser and give a multimodal model the page as it was designed: columns, labels, callouts, diagrams, handwriting, and spatial relationships intact. Pair that view with the extracted model for grounded document workflows.
Live comparison
Choose a real document—including a 100 MiB, 1,000-page PDF. Both panes receive the same public R2 URL: the left is a scrollable native PDF viewer; the right extracts and renders page one with @boxpdf/reader and @boxpdf/html-writer. The metrics describe the right-hand conversion, measured live in your browser.
Loading the live demo…
Large documents feel small
Opening a document does not decode every page. The reader resolves the cross-reference data, fetches page one, and leaves the remaining 999 pages on the source until requested.
Local Node 24 benchmark, seven warm/cold runs, synthetic 1,000-page PDF. Hardware and document complexity vary.
The memory gate seeks directly to page 10,000 with compact xrefs while retaining bounded caches.
Measured process memory
Same logical PDF, isolated Node 24 processes. PDF.js and unpdf use their complete-Uint8Array APIs; @boxpdf/reader uses a random-access source.
Peak RSS includes a ~46 MiB Node baseline. Results vary by OS and dependency version. Run the benchmark yourself.
Absolute positioning, original geometry, SVG vectors, embedded font programs, and page paint order. Use it for viewers, previews, and PDF-to-HTML conversion.
Get clean reading order, nested sections, lists, cards, addresses, financial summaries, and tables that continue across pages. See why the page layout matters →
npm install @boxpdf/reader @boxpdf/html-writer
openPdf(httpSource(url))
openPdf(blobSource(file))
openPdf(memorySource(bytes))HTTP range requests, browser files, in-memory bytes, or your own size + read(offset, length) source.
for (let i = 0; i < await pdf.getPageCount(); i++) {
await write(pageToHtml(await pdf.getPage(i), {
profile: "visual"
}));
}Consume a page at a time without retaining the original PDF or completed HTML output.