The first step of indexing — turning raw files into one common Document object, and the quiet ways that step can fail
Every source format — PDF, HTML, a database row, a plain text file — stores and structures content differently. A document loader's job is simple: take a raw file and convert it into a standardized Document object that the rest of the pipeline can work with, regardless of where the content originally came from. Loading is also where more real-world RAG quality is lost than anywhere else in the pipeline, because a bad extraction fails silently — the pipeline keeps running, it just runs on garbage.
{"source": "policy.pdf", "page": 4}TextLoader (.txt), Docx2txtLoader / UnstructuredWordDocumentLoader (Word), UnstructuredMarkdownLoader (Markdown), BSHTMLLoader / WebBaseLoader (HTML/web pages) — these formats store text as text, so extraction is close to lossless.CSVLoader (one Document per row, columns become metadata or content), JSONLoader (with a jq-style schema to pick which fields become content), SQLDatabaseLoader (database tables, one Document per row or per query result).NotionDBLoader, ConfluenceLoader, GoogleDriveLoader, S3DirectoryLoader, Slack/GitHub loaders — pull content directly from a live system rather than a local file, usually returning the same metadata the system itself tracks (author, last-modified, URL).Unstructured.io and LlamaIndex's readers handle dozens of formats behind one interface and add layout-aware parsing (detecting titles, list items, and tables as distinct elements rather than one flat text blob) — a strong default when the source formats are mixed or unknown ahead of time.PDF is a page-layout format, not a text format — it stores where characters are drawn on a page, not the logical reading order of a paragraph. This causes specific, common problems:
camelot, pdfplumber, or Unstructured's table detection) is often needed to preserve the row/column relationship as markdown or structured data.Metadata isn't an afterthought — it's the field you'll filter on, cite from, and debug with, so it's worth deciding up front what every document type needs to carry:
The last field — a stable document id — matters more than it looks: without it, updating or deleting a source document means you have no reliable way to find and remove its old chunks from the vector database (see Production Concerns → incremental indexing).
None of these throw exceptions. The only reliable way to catch them is spot-checking extracted page_content against the original source for a sample of documents before trusting the rest of the pipeline — treat loader output as untrusted until verified, the same way you'd validate any other data ingestion step.
Metadata survives all the way through chunking, embedding, and storage in the vector database — that's what makes it possible to filter retrieval to a specific source or date range, and to cite exactly which page of which document a final answer came from, which is exactly what fixes the explainability gap described in What Is RAG?.