A PDF is a container, not a sheet of paper
PDFs can carry whole files inside them, in a name tree the page never shows. How embedded files work, why PDF/A-3 exists, and the bug that loses old attachments.
Most people picture a PDF as a stack of printed pages that happens to live on a computer. It’s a reasonable mental model and it’s wrong in a way that matters. A PDF is a container. The pages are one of the things it holds, alongside fonts, colour profiles, metadata, form definitions, bookmarks and, if you want, entire other files of any type at all.
That last one is the least known and the most useful. A spreadsheet, an XML document, a folder’s worth of raw measurements: all of it can live inside the PDF, travel with it, and be pulled back out by any reader. files.co does it in the browser with attach files to a PDF, and it’s worth understanding what actually happens to the file when you do.
What a PDF carries besides the page
| What it holds | Where it lives | Survives a merge or a re-save? |
|---|---|---|
| The page content | The document’s object tree, defined by ISO 32000 | Yes |
| Attached files | The /EmbeddedFiles name tree, and older files put them on a page annotation |
Not always — the old placement is what tools quietly drop |
| Metadata | The document info dictionary and an XMP stream | Often, and that includes the author and software you did not mean to send |
| Active content | /OpenAction, /AA, /Names/JavaScript, and per-page and per-annotation actions |
Yes, unless you remove it deliberately |
| Compression | Applied per stream, and it is not encryption | Yes |
Where an attachment lives
Where an attachment lives
Every PDF has a catalog, the root object that says where everything else is. Hanging off it there can be a name tree, and inside that a branch called /EmbeddedFiles. That branch maps names to file specifications, and each file specification points at a stream holding the actual bytes of your attachment, compressed.
A name tree is not a flat list. The specification lets it be a proper tree: a root node with /Kids pointing at intermediate nodes, each covering an alphabetical slice of the names, so that a reader can find one entry among thousands without walking the lot. Small documents usually get a single node with a flat /Names array. Big ones, or ones produced by systems that expect to hold a lot of attachments, get the branching version.
This is the whole reason attachments show up in a reader’s paperclip panel rather than on a page. They’re referenced from the document’s structure, not from the page content. Nothing is drawn, nothing shifts, the layout is untouched. Someone who never opens the panel will never know they’re there.
The bug that quietly loses your old attachments
Here’s where the tree structure stops being trivia. Add an attachment to a PDF that already had some, and a library that just appends can create a /Names array right next to the existing /Kids. A node with both keys is invalid. Readers handle invalid nodes however they feel like, and a common outcome is that the panel shows only the attachments you just added while the earlier ones vanish from view. The bytes are still in the file. Nobody can reach them.
That’s a nasty failure because it looks like success. You attached a file, the file is there, you shipped the document. The three attachments the previous person put in are gone from every panel that opens it.
The engine behind our tool flattens the tree into a single sorted /Names array before attaching, so the new entries land in the same array as the old ones, and sorts it again afterwards, because the specification asks for entries in key order and appending doesn’t keep them that way. It’s an unglamorous fix for a problem you’d only discover months later.
PDF/A-3 and the hybrid invoice
Attachments are also why one archival standard exists at all. As covered in PDF/A, explained, PDF/A-2 tightened PDF into something predictable enough to archive for decades. PDF/A-3 is nearly the same standard with one deliberate loosening: it allows arbitrary files of any type to be embedded alongside the archived pages.
That single change is what hybrid electronic invoicing is built on. A Factur-X or ZUGFeRD invoice is one file that is simultaneously a human-readable page and a machine-readable XML document, because the XML rides inside the PDF/A-3. No pairing, no matching filenames, no risk of the two halves disagreeing after someone edits one of them.
The standard also has a field for saying why a file is attached: whether it’s the source the document was generated from, supplementary data, an alternative representation, and so on. Our tool writes it as unspecified by default rather than guessing, because claiming a spreadsheet is the authoritative source of a document when we have no idea is worse than admitting we don’t know. If you need conformance for a specific archival profile, convert to PDF/A is a separate step with its own rules.
Compression is not encryption
The embedded stream is compressed with Flate. That is a size optimisation and nothing else. An attachment inside a PDF is not encrypted, and anyone holding the file can extract it in a couple of clicks.
Say it out loud because the container metaphor invites the opposite intuition: things “inside” something feel protected. They aren’t. Treat an attachment exactly like an email attachment, because in terms of who can read it, that’s what it is. If you’re in the habit of doing a final pass before a document goes out, attachments belong on that checklist next to metadata; what to check before sending a PDF covers the rest of it.
What you actually get
Before anything is modified, the tool lists what the document already carries, with names and real sizes, and lets you save those out. Existing attachments are always preserved. A new file whose name collides with an old one gets numbered rather than overwriting anything.
The practical ceiling is twenty files and 50 MB per pass, lower on an iPhone where the browser hands a page much less memory. Expect the document to grow by roughly the compressed size of what you put in, which for CSV or XML is very little and for a JPEG or a zip is close to the full size, since those are already squeezed.
One refusal worth knowing: a password-protected PDF is rejected instead of being rewritten half-blind. And support varies at the far end. Desktop readers handle attachments well, mobile ones often don’t show a panel at all, so if the recipient is on a phone, tell them what’s inside rather than assuming they’ll spot the paperclip.
Frequently asked questions
Can a PDF contain other files?
Yes. A PDF is a container, not just a page: it can carry arbitrary attached files inside it — a spreadsheet, an XML invoice, another PDF. The modern place for them is the `/EmbeddedFiles` name tree at the document level. Older files often attached them to a page annotation instead, which is why some attachments vanish when a tool rewrites the document.
Why did the attachments disappear when I merged two PDFs?
Because a lot of tools only copy the attachments they find in the modern location and silently drop the ones attached to a page annotation. Nothing errors, the merge looks fine, and the file is simply lighter than it was. If a PDF is carrying something you need, check it before and after any operation that rewrites the document.
Is a compressed PDF protected?
No, and the two get confused constantly. Compression makes the streams smaller; anyone can still open the file and read every word. Encryption is what stops someone reading it, and that is a separate operation — [protecting a PDF with a password](/protect-pdf/) applies AES. A file can be heavily compressed and completely readable by anyone who has it.
What is PDF/A-3 for?
It is the archival profile that allows arbitrary attachments, which is exactly what a hybrid invoice needs: a human-readable page with the machine-readable XML riding along inside the same file. That flexibility is why some administrations require it and why pure archives often prefer PDF/A-2, which is stricter about what can come along.