pdf-parse vs pdf2json
Extracting Text and Data from PDFs in Node.js
pdf-parsepdf2json

Extracting Text and Data from PDFs in Node.js

pdf-parse and pdf2json are two popular Node.js libraries used to extract content from PDF files, but they serve different primary purposes. pdf-parse is a lightweight wrapper around pdf.js designed specifically for extracting raw text content from PDF pages with minimal configuration. It returns a simple JSON object containing text per page, making it ideal for search indexing or basic text analysis. pdf2json, on the other hand, converts the entire PDF structure into a detailed JSON representation, preserving not just text but also layout coordinates, font information, and form field data. This makes pdf2json better suited for applications requiring precise layout reconstruction, form processing, or visual analysis of the document structure.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
pdf-parse021021.3 MB289 months agoApache-2.0
pdf2json02,2098.2 MB764 months agoApache-2.0

pdf-parse vs pdf2json: Choosing the Right Tool for PDF Extraction

When working with PDFs in a Node.js environment, developers often face a choice between extracting raw text for analysis or parsing the full document structure for layout preservation. pdf-parse and pdf2json address these two distinct needs. While both libraries run on the server and handle PDF processing, their output formats and underlying capabilities differ significantly. Let's explore how they compare in real-world scenarios.

📄 Core Purpose: Text Extraction vs. Structural Parsing

pdf-parse is built for one thing: getting text out of a PDF as quickly and easily as possible. It acts as a thin wrapper around Mozilla's pdf.js library, stripping away the complexity of the rendering engine to give you a clean string of text per page. It does not care about where the text sits on the page or what font was used.

const pdf = require('pdf-parse');
const fs = require('fs');

const dataBuffer = fs.readFileSync('document.pdf');

pdf(dataBuffer).then(function(data) {
  // data.text contains the full text of the PDF
  // data.numpages gives the page count
  // data.info contains metadata like title and author
  console.log(data.text);
});

pdf2json takes a different approach. It parses the PDF into a structured JSON object that represents the visual layout. Every text element includes its x/y coordinates, font size, and rotation. This allows developers to rebuild the document visually or extract data based on position rather than just content flow.

const PDFParser = require('pdf2json');
const pdfParser = new PDFParser();

pdfParser.on('pdfParser_dataReady', (pdfData) => {
  // pdfData.formImage.Pages contains an array of page objects
  // Each page has 'Texts' array with x, y, w, h, and R (rotation) for every snippet
  console.log(JSON.stringify(pdfData.formImage.Pages[0].Texts));
});

pdfParser.loadPDF('document.pdf');

🧩 Handling Layout and Coordinates

One of the biggest differences lies in how they handle spatial information. If you are building a tool that needs to highlight specific words on a rendered canvas or extract data from a specific column in a table, coordinates are essential.

pdf-parse discards this information entirely. The page object in its response only contains the textContent and a count of lines if requested, but no positional data. You cannot determine where a specific sentence appears on the page.

// pdf-parse output structure
// No x/y coordinates available
const result = await pdf(dataBuffer);
const pageOne = result.pages[0]; 
// pageOne only has: { textContent: "...", lines: [...] }

pdf2json excels here. Every text fragment comes with precise x, y, w (width), and h (height) properties relative to the page dimensions. This is critical for applications like invoice processing where "Total Amount" is always found at a specific coordinate.

// pdf2json output structure
// Detailed coordinates for every text run
const texts = pdfData.formImage.Pages[0].Texts;
texts.forEach(textRun => {
  // textRun.x, textRun.y, textRun.w, textRun.h are available
  if (textRun.x > 400 && textRun.y < 100) {
     // Logic for top-right corner content
  }
});

📝 Working with Forms and Interactive Fields

If your workflow involves processing filled-out PDF forms (FDF/AcroForms), the choice becomes even clearer.

pdf-parse generally ignores form field data. It treats the visual representation of the filled text as regular page content. If a user types into a form field, pdf-parse might pick it up as part of the general text stream, but it won't identify it as a specific field named "email_address" or "signature".

// pdf-parse cannot distinguish form fields from static text
// You get a blob of text without field names
const data = await pdf(formBuffer);
// data.text includes the filled values but no mapping to field IDs

pdf2json was originally designed with form processing in mind. It explicitly parses form fields and includes them in the JSON output, often separating them from the static page text. This allows you to map values directly to database columns based on field names.

// pdf2json identifies form fields specifically
// Fields are often accessible via the 'Fields' property in the page object
const fields = pdfData.formImage.Pages[0].Fields;
fields.forEach(field => {
  // field.Name, field.Value, field.Type are available
  console.log(`${field.Name}: ${field.Value}`);
});

⚙️ Configuration and Ease of Use

Simplicity is a major factor for quick scripts. pdf-parse offers a zero-config experience. You pass a buffer or a file path, and you get text. There are no event listeners to manage or complex options to set for standard use cases.

// Simple async/await pattern
async function extractText(path) {
  const buffer = fs.readFileSync(path);
  const data = await pdf(buffer);
  return data.text;
}

pdf2json uses an event-driven architecture, which can be slightly more verbose for simple tasks. You must instantiate the parser, attach a listener for the pdfParser_dataReady event, and handle errors separately. This pattern is powerful for streaming large files but adds boilerplate for simple scripts.

// Event-based pattern required
function extractStructure(path) {
  return new Promise((resolve, reject) => {
    const parser = new PDFParser();
    parser.on('pdfParser_dataReady', resolve);
    parser.on('pdfParser_dataError', reject);
    parser.loadPDF(path);
  });
}

🚀 Performance and Memory Considerations

Because pdf-parse stops processing once it extracts the text strings, it generally consumes less memory and CPU for simple text extraction tasks. It does not build the heavy internal representation of the page layout.

pdf2json generates a much larger output object because it stores metadata for every single visual element. For a text-heavy document with complex formatting, the resulting JSON from pdf2json can be significantly larger than the raw text from pdf-parse. This trade-off is necessary if you need the layout data, but it is a cost to consider for high-volume processing pipelines where only text matters.

🤝 Similarities: Shared Ground

Despite their differences, both libraries share some common traits that make them viable for server-side Node.js applications.

1. 🖥️ Server-Side Focus

Both libraries are designed primarily for Node.js environments. While pdf.js (the engine behind pdf-parse) runs in browsers, pdf-parse wraps it specifically for server usage without DOM dependencies. pdf2json is also a pure Node.js module.

// Both work seamlessly in Express.js routes
app.post('/upload', async (req, res) => {
  const buffer = req.file.buffer;
  // Can use either library here depending on needs
});

2. 📄 Multi-Page Support

Both libraries handle multi-page documents naturally. They return data structures that iterate over pages, allowing you to process documents of any length without manual splitting.

// pdf-parse
data.pages.forEach(page => console.log(page.textContent));

// pdf2json
pdfData.formImage.Pages.forEach(page => console.log(page.Texts));

3. 🛡️ No External Binary Dependencies

Unlike some PDF tools that require installing system-level binaries like poppler or ghostscript, both pdf-parse and pdf2json are pure JavaScript (or bundle their own WASM/JS engines). This makes deployment to serverless environments like AWS Lambda or Vercel much simpler.

# No need for apt-get install poppler-utils
npm install pdf-parse
# or
npm install pdf2json

📊 Summary: Key Differences

Featurepdf-parsepdf2json
Primary OutputRaw text stringsStructured JSON with layout
Coordinates❌ Not available✅ Precise x/y/w/h included
Form Fields❌ Treated as regular text✅ Explicitly parsed and named
API StylePromise-based (async/await)Event-based (listeners)
Output SizeSmall (text only)Large (metadata heavy)
Best ForSearch, indexing, NLPForms, layout analysis, reconstruction

💡 The Big Picture

pdf-parse is your go-to tool when you treat the PDF as a document of words. If you are building a search engine, a chatbot that reads PDFs, or a simple archiving system, this library gives you the text with the least amount of friction. It respects the "content over layout" philosophy.

pdf2json is the specialist for when the position of the text matters as much as the text itself. If you are automating data entry from invoices, processing tax forms, or need to regenerate a visual representation of the PDF in a custom viewer, the detailed structural data it provides is indispensable.

Final Thought: Don't over-engineer your solution. If you just need the words, pdf-parse is faster and simpler. If you need to know exactly where those words live on the page or what form field they belong to, pdf2json is the only choice between the two.

How to Choose: pdf-parse vs pdf2json

  • pdf-parse:

    Choose pdf-parse if your goal is simply to extract readable text from a PDF for indexing, searching, or natural language processing. It is the better option when you need a quick, low-memory solution that ignores complex layout details and focuses solely on the textual content. Its API is straightforward and requires no configuration for standard text extraction tasks.

  • pdf2json:

    Choose pdf2json if you need to preserve the spatial layout of the document, extract data from filled forms, or analyze the specific positioning of elements on the page. It is the right choice for applications that need to reconstruct the visual structure of the PDF or process interactive form fields, as it provides detailed coordinate and metadata information that pdf-parse discards.

README for pdf-parse

pdf-parse

Pure TypeScript, cross-platform module for extracting text, images, and tables from PDFs.
Run 🤗 directly in your browser or in Node!

npm version npm downloads node version tests tests biome vitest codecov test & coverage reports


Getting Started with v2 (Coming from v1)

// v1
// const pdf = require('pdf-parse');
// pdf(buffer).then(result => console.log(result.text));

// v2
const { PDFParse } = require('pdf-parse');
// import { PDFParse } from 'pdf-parse';

async function run() {
	const parser = new PDFParse({ url: 'https://bitcoin.org/bitcoin.pdf' });

	const result = await parser.getText();
	console.log(result.text);
}

run();

Features demo

Installation

npm install pdf-parse
# or
pnpm add pdf-parse
# or
yarn add pdf-parse
# or
bun add pdf-parse

CLI Installation

For command-line usage, install the package globally:

npm install -g pdf-parse

Or use it directly with npx:

npx pdf-parse --help

For detailed CLI documentation and usage examples, see: CLI Documentation

Usage

getHeader — Node Utility: PDF Header Retrieval and Validation

// Important: getHeader is available from the 'pdf-parse/node' submodule
import { getHeader } from 'pdf-parse/node';

// Retrieve HTTP headers and file size without downloading the full file.
// Pass `true` to check PDF magic bytes via range request.
// Optionally validates PDFs by fetching the first 4 bytes (magic bytes).
// Useful for checking file existence, size, and type before full parsing.
// Node only, will not work in browser environments.
const result = await getHeader('https://bitcoin.org/bitcoin.pdf', true);

console.log(`Status: ${result.status}`);
console.log(`Content-Length: ${result.size}`);
console.log(`Is PDF: ${result.isPdf}`);
console.log(`Headers:`, result.headers);

getInfo — Extract Metadata and Document Information

import { readFile } from 'node:fs/promises';
import { PDFParse } from 'pdf-parse';

const link = 'https://mehmet-kozan.github.io/pdf-parse/pdf/climate.pdf';
// const buffer = await readFile('reports/pdf/climate.pdf');
// const parser = new PDFParse({ data: buffer });

const parser = new PDFParse({ url: link });
const result = await parser.getInfo({ parsePageInfo: true });
await parser.destroy();

console.log(`Total pages: ${result.total}`);
console.log(`Title: ${result.info?.Title}`);
console.log(`Author: ${result.info?.Author}`);
console.log(`Creator: ${result.info?.Creator}`);
console.log(`Producer: ${result.info?.Producer}`);

// Access parsed date information
const dates = result.getDateNode();
console.log(`Creation Date: ${dates.CreationDate}`);
console.log(`Modification Date: ${dates.ModDate}`);

// Links, pageLabel, width, height (when `parsePageInfo` is true)
console.log('Per-page information:');
console.log(JSON.stringify(result.pages, null, 2));

getText — Extract Text

import { PDFParse } from 'pdf-parse';

const parser = new PDFParse({ url: 'https://bitcoin.org/bitcoin.pdf' });
const result = await parser.getText();
// to extract text from page 3 only:
// const result = await parser.getText({ partial: [3] });
await parser.destroy();
console.log(result.text);

For a complete list of configuration options, see:

Usage Examples:

getScreenshot — Render Pages as PNG

import { readFile, writeFile } from 'node:fs/promises';
import { PDFParse } from 'pdf-parse';

const link = 'https://bitcoin.org/bitcoin.pdf';
// const buffer = await readFile('reports/pdf/bitcoin.pdf');
// const parser = new PDFParse({ data: buffer });

const parser = new PDFParse({ url: link });

// scale:1 for original page size.
// scale:1.5 50% bigger.
const result = await parser.getScreenshot({ scale: 1.5 });

await parser.destroy();
await writeFile('bitcoin.png', result.pages[0].data);

Usage Examples:

  • Limit output resolution or specific pages using ParseParameters
  • getScreenshot({scale:1.5}) — Increase rendering scale (higher DPI / larger image)
  • getScreenshot({desiredWidth:1024}) — Request a target width in pixels; height scales to keep aspect ratio
  • imageDataUrl (default: true) — include base64 data URL string in the result.
  • imageBuffer (default: true) — include a binary buffer for each image.
  • Select specific pages with partial (e.g. getScreenshot({ partial: [1,3] }))
  • partial overrides first/last.
  • Use first to render the first N pages (e.g. getScreenshot({ first: 3 })).
  • Use last to render the last N pages (e.g. getScreenshot({ last: 2 })).
  • When both first and last are provided they form an inclusive range (first..last).

getImage — Extract Embedded Images

import { readFile, writeFile } from 'node:fs/promises';
import { PDFParse } from 'pdf-parse';

const link = new URL('https://mehmet-kozan.github.io/pdf-parse/pdf/image-test.pdf');
// const buffer = await readFile('reports/pdf/image-test.pdf');
// const parser = new PDFParse({ data: buffer });

const parser = new PDFParse({ url: link });
const result = await parser.getImage();
await parser.destroy();

await writeFile('adobe.png', result.pages[0].images[0].data);

Usage Examples:

  • Exclude images with width or height <= 50 px: getImage({ imageThreshold: 50 })
  • Default imageThreshold is 80 (pixels)
  • Useful for excluding tiny decorative or tracking images.
  • To disable size-based filtering and include all images, set imageThreshold: 0.
  • imageDataUrl (default: true) — include base64 data URL string in the result.
  • imageBuffer (default: true) — include a binary buffer for each image.
  • Extract images from specific pages: getImage({ partial: [2,4] })

getTable — Extract Tabular Data

import { readFile } from 'node:fs/promises';
import { PDFParse } from 'pdf-parse';

const link = new URL('https://mehmet-kozan.github.io/pdf-parse/pdf/simple-table.pdf');
// const buffer = await readFile('reports/pdf/simple-table.pdf');
// const parser = new PDFParse({ data: buffer });

const parser = new PDFParse({ url: link });
const result = await parser.getTable();
await parser.destroy();

// Pretty-print each row of the first table
for (const row of result.pages[0].tables[0]) {
	console.log(JSON.stringify(row));
}

Exception Handling & Type Usage

import type { LoadParameters, ParseParameters, TextResult } from 'pdf-parse';
import { PasswordException, PDFParse, VerbosityLevel } from 'pdf-parse';

const loadParams: LoadParameters = {
	url: 'https://mehmet-kozan.github.io/pdf-parse/pdf/password-123456.pdf',
	verbosity: VerbosityLevel.WARNINGS,
	password: 'abcdef',
};

const parseParams: ParseParameters = {
	first: 1,
};

// Initialize the parser class without executing any code yet
const parser = new PDFParse(loadParams);

function handleResult(result: TextResult) {
	console.log(result.text);
}

try {
	const result = await parser.getText(parseParams);
	handleResult(result);
} catch (error) {
	// InvalidPDFException
	// PasswordException
	// FormatError
	// ResponseException
	// AbortException
	// UnknownErrorException
	if (error instanceof PasswordException) {
		console.error('Password must be 123456\n', error);
	} else {
		throw error;
	}
} finally {
	// Always call destroy() to free memory
	await parser.destroy();
}

Web / Browser

CDN Usage

<!-- ES Module -->
<script type="module">

  import {PDFParse} from 'https://cdn.jsdelivr.net/npm/pdf-parse@latest/dist/pdf-parse/web/pdf-parse.es.js';
  //// Available Worker Files
  // pdf.worker.mjs
  // pdf.worker.min.mjs
  // If you use a custom build or host pdf.worker.mjs yourself, configure worker accordingly.
  PDFParse.setWorker('https://cdn.jsdelivr.net/npm/pdf-parse@latest/dist/pdf-parse/web/pdf.worker.mjs');

  const parser = new PDFParse({url:'https://mehmet-kozan.github.io/pdf-parse/pdf/bitcoin.pdf'});
  const result = await parser.getText();

  console.log(result.text)
</script>

CDN Options: https://www.jsdelivr.com/package/npm/pdf-parse

  • https://cdn.jsdelivr.net/npm/pdf-parse@latest/dist/pdf-parse/web/pdf-parse.es.js
  • https://cdn.jsdelivr.net/npm/pdf-parse@2.4.5/dist/pdf-parse/web/pdf-parse.es.js
  • https://cdn.jsdelivr.net/npm/pdf-parse@latest/dist/pdf-parse/web/pdf-parse.umd.js
  • https://cdn.jsdelivr.net/npm/pdf-parse@2.4.5/dist/pdf-parse/web/pdf-parse.umd.js

Worker Options:

  • https://cdn.jsdelivr.net/npm/pdf-parse@latest/dist/pdf-parse/web/pdf.worker.mjs
  • https://cdn.jsdelivr.net/npm/pdf-parse@latest/dist/pdf-parse/web/pdf.worker.min.mjs

Similar Packages

Benchmark Note: The benchmark currently runs only against pdf2json. I don't know the current state of pdf2json — the original reason for creating pdf-parse was to work around stability issues with pdf2json. I deliberately did not include pdf-parse or other pdf.js-based packages in the benchmark because dependencies conflict. If you have recommendations for additional packages to include, please open an issue, see benchmark results.

Supported Node.js Versions(20.x, 22.x, 23.x, 24.x)

  • Supported: Node.js 20 (>= 20.16.0), Node.js 22 (>= 22.3.0), Node.js 23 (>= 23.0.0), and Node.js 24 (>= 24.0.0).
  • Not supported: Node.js 21.x, and Node.js 19.x and earlier.

Integration tests run on Node.js 20–24, see test_integration.yml.

Unsupported Node.js Versions (18.x, 19.x, 21.x)

Requires additional setup see docs/troubleshooting.md.

Worker Configuration & Troubleshooting

See docs/troubleshooting.md for detailed troubleshooting steps and worker configuration for Node.js and serverless environments.

  • Worker setup for Node.js, Next.js, Vercel, AWS Lambda, Netlify, Cloudflare Workers.
  • Common error messages and solutions.
  • Manual worker configuration for custom builds and Electron/NW.js.
  • Node.js version compatibility.

If you encounter issues, please refer to the Troubleshooting Guide.

Contributing

When opening an issue, please attach the relevant PDF file if possible. Providing the file will help us reproduce and resolve your issue more efficiently. For detailed guidelines on how to contribute, report bugs, or submit pull requests, see: contributing to pdf-parse