n8n can read a PDF in one node, but only if the PDF has a real text layer. Everything hard about PDF automation comes down to that one distinction.
A PDF is not a document format so much as a print format that got promoted. Some PDFs carry a proper text layer, and for those the Extract From File node is a single drag away from working. Others are a photograph of a page wearing a PDF extension, and no amount of node configuration will pull words out of them. Most workflows that fail in production fail because nobody checked which kind was arriving.
This walks through the working path first, then the failure that catches people three weeks in.
Table of contents
- Get the file into the workflow as binary data
- Extract the text with Extract From File
- Parse the text into fields you can actually use
- The scanned-PDF wall, and how to see it coming
- Process many documents without melting the execution
- Where the workflow actually lives
- How this fits the rest of the stack
- FAQ
Get the file into the workflow as binary data
Before anything can read a PDF, the PDF has to be in the workflow as binary data attached to an item. n8n keeps binary payloads separate from JSON, under a named property, and that name matters for every node downstream.
Three common entry points:
- Form Trigger with a file upload field. The binary lands on the property named after the field.
- HTTP Request with the response format set to
File. Set the output property explicitly rather than accepting the default. - Read/Write Files From Disk, for a self-hosted instance with a mounted volume.
Whichever one you use, open the node output and look at the Binary tab. You want a mimeType of application/pdf and a non-trivial fileSize. A few hundred bytes usually means you captured an error page instead of a document, and the extraction node will fail with something unhelpful two nodes later.
Extract the text with Extract From File
The Extract From File node with the operation set to PDF is the whole happy path. Point it at the binary property, run it, and the output JSON carries the document text plus metadata.
The fields worth knowing:
text— the full extracted text, page breaks included.numpages— useful as a sanity check and as a loop bound.info— the PDF metadata dictionary, where Title and Author live if the producer bothered to set them.- Max Pages — an option, not a default. Set it when documents can be large, or one 400-page attachment will hold the execution open.
The text comes out as one string with the layout flattened. Tables in particular arrive as a stream of cells with no column structure, which is why the next section exists.
Parse the text into fields you can actually use
Extracted text is rarely the deliverable. What the workflow usually wants is five fields off an invoice, or a decision about where to route the document.
For structured, predictable documents, a Code node with regular expressions is faster, cheaper and more debuggable than anything involving a model:
const text = $input.first().json.text;
const invoice = text.match(/Invoice\s*#?\s*([A-Z0-9-]+)/i)?.[1] ?? null;
const total = text.match(/Total\s*[:\s]\s*\$?([\d,]+\.\d{2})/i)?.[1] ?? null;
const dated = text.match(/Date\s*[:\s]\s*(\d{4}-\d{2}-\d{2})/)?.[1] ?? null;
return [{ json: { invoice, total, dated, ok: Boolean(invoice && total) } }];
Note the ok flag. Give every parse an explicit success condition and route failures to a human queue with an IF node. A workflow that silently writes null into a finance spreadsheet is worse than one that stops.
For documents whose layout varies — supplier invoices from forty different vendors — regex stops paying off and a model with a strict output schema is the better tool. Feed it the extracted text, not the raw file, and keep the temperature low. Which brings up a related problem covered in its own post: models return different answers to identical inputs unless you configure them not to.
The scanned-PDF wall, and how to see it coming
Here is the failure that reaches production. Extract From File returns an empty or near-empty text field, no error is thrown, and every node downstream processes nothing with great enthusiasm.
The cause is that the PDF has no text layer. It is a scan, an export from a photo, or a document someone printed and re-scanned to sign. The bytes are an image. There is nothing for a text extractor to extract.
Catch it explicitly rather than discovering it in a report:
const text = ($input.first().json.text ?? '').trim();
const pages = $input.first().json.numpages ?? 1;
// Fewer than ~50 characters per page means no usable text layer.
if (text.length / pages < 50) {
return [{ json: { needsOcr: true, chars: text.length, pages } }];
}
return [{ json: { needsOcr: false, text } }];
Route needsOcr down a separate branch. The realistic options are an OCR service via HTTP Request, converting pages to images and sending them to a vision-capable model, or — often the right answer — pushing the problem back to whoever is producing the scans. A supplier who can send a real PDF instead of a phone photo of a printout will save more engineering time than any OCR pipeline.
Process many documents without melting the execution
One PDF is a demo. A folder of six hundred is the actual job, and it is where naive workflows fall over: memory climbs, the execution times out, and n8n has to hold every binary payload for every item at once.
The fix is the Loop Over Items node with a small batch size, so only a handful of documents are in memory at any moment. Inside the loop, extract, parse and write the result somewhere durable — a database row, a sheet row, an API call — then let the batch fall out of scope.
Two settings that matter more than they look:
- Batch size. Start at 5 for PDF work. Text extraction is memory-hungry per item in a way that most nodes are not.
- Always Output Data, off. With it on, a failed extraction still emits an item and the failure travels silently downstream.
Persist results as the loop runs rather than accumulating them for a single write at the end. If the execution dies at document 500, you want 499 rows already saved, not an empty table and a long face.
Where the workflow actually lives
A PDF pipeline is not a workflow so much as a small service. It needs a place to run on a schedule, a database to write to, credentials it can hold safely, and logs you can read when a supplier changes their invoice template and the parse quietly starts returning null.
Self-hosting that means a server, TLS, a Postgres instance behind n8n rather than the bundled SQLite, backups, and an upgrade path. Each of those is a small job. Together they are the reason plenty of good workflows never leave someone’s laptop.
On RunxBuild, n8n is a managed tool: pick a plan, get a URL, set environment variables in the dashboard, and put a managed Postgres next to it. An n8n instance on a $6 Basic plan with a database beside it is enough to run document workflows properly, with runtime logs in the same place as the deploy that shipped them.
How this fits the rest of the stack
PDF processing looks like a text problem and is really an infrastructure problem: the extraction is one node, and the rest is storage, scheduling, credentials, retries and somewhere to look when it breaks. Before committing to a design, it is worth pricing the pieces together — the n8n instance, the database it writes to, the storage the documents sit in. The RunxBuild hosting calculator puts those line items on one page so the total is a number rather than a surprise.
Useful related references:
- Access Blocked: Google Verification and Self-Hosted n8n Credentials
- n8n vs Make: Where the Complexity Goes
- n8n Use Cases: What It Is Genuinely Good At, and What It Is Not
- Services on RunxBuild
FAQ
Can n8n read a scanned PDF?
Not with the Extract From File node. That node reads the text layer, and a scan has none — it returns empty text and no error. You need OCR first, either through an external service called via HTTP Request or by converting pages to images and sending them to a vision-capable model. Detect the case explicitly by checking extracted characters per page before assuming success.
Which node extracts text from a PDF in n8n?
Extract From File, with the operation set to PDF. It takes a binary property as input and returns text, numpages and an info metadata object. It replaced the older standalone PDF node, so older tutorials may reference a node name you will not find in the current editor.
How do I handle password-protected PDFs?
Extract From File accepts a password in its node options. Store it as a credential or an environment variable rather than typing it into the node, since workflow JSON is frequently exported, shared and committed to version control.
Why does my PDF workflow run out of memory?
Because every item’s binary payload is held at once. Wrap the extraction in a Loop Over Items node with a batch size around 5, and write each batch’s results to durable storage inside the loop rather than accumulating everything for one write at the end.
Is a Code node or an AI model better for parsing invoices?
Regex in a Code node wins when the layout is stable: it is faster, free, deterministic and easy to debug. A model earns its cost when layouts vary across many senders. Whichever you pick, add an explicit success check and route failures to a human rather than writing nulls downstream.