Every LangChain loader — PDF, web page, database — produces the same shape: content plus metadata. Build that shape yourself.
1One Shape, Every Source
The genius of the Document abstraction isn't complexity — it's uniformity. Whether your source is a PDF, a Notion page, a database row, or a plain text file, a LangChain loader normalizes it into the exact same Document shape. Everything downstream (splitters, embedders, retrievers) only ever needs to know how to handle one interface.
2Metadata Is Not Optional Decoration
It's tempting to treat metadata as a nice-to-have. It's actually load-bearing: without it, once content is chunked and embedded, there is no way to trace a retrieved chunk back to its original source — no citations, no debugging a wrong answer, no filtering retrieval by document type. Attaching metadata at load time is the only point where that provenance information is easy to capture.
3Step-by-Step Breakdown
Module 4 wires your chains and memory into external documents — RAG, but built the LangChain way this time. It starts with the Document class: every loader in LangChain, no matter the source (PDF, web page, database), returns Document objects with exactly two fields: page_content and metadata.
That metadata dict isn't decoration — it's what lets you trace an answer back to which file, page, or URL it came from later, exactly like the source citations you may have built in other RAG work. A loader's whole job is producing well-formed Documents, content plus provenance.
Build a Document Loader Yourself. Finish load_text_file(): wrap the given content in a Document, with metadata recording which file it came from. This exact shape — content plus a source-tracking metadata dict — is what every real LangChain document loader produces, regardless of the source format.
Why do all LangChain document loaders return a Document with a metadata field, rather than just the raw page content?
- →Metadata tracks provenance — where the content came from — which is what later lets a RAG system cite its sources and trace a wrong answer back to a specific document.
- →It compresses the page content to save memory.
Next: a document is rarely small enough to embed whole. Text splitters break a Document into chunks — while carrying its metadata forward into every single one.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Preserve Source Metadata All the Way to the UI Layer
Whatever metadata a Document carries at load time should survive through chunking, retrieval, and generation, so a final UI can still cite the original source as real, accessible text.
<a href="#handbook.txt">Source: handbook.txt</a>SEO Implications
- 1
Target 'LangChain Document class' and 'LangChain document loader example' as distinct searches
These are among the first classes developers search for a working example of when starting a LangChain RAG project.
Best Practices
Always Attach Meaningful Metadata at Load Time
Load time is when provenance information (file name, page number, URL) is most readily available — capture it into metadata immediately, since it becomes much harder to reconstruct once content has already been chunked and embedded.
Frequent Bugs
A custom loader that returns raw strings instead of Document objects, breaking compatibility with every downstream splitter and retriever expecting the standard shape.
Always wrap loaded content in a Document with at least a page_content field and a metadata dict, even if metadata is initially sparse — downstream components are built against this interface.
Real-World Examples
Multi-Format Knowledge Base
A knowledge base ingesting PDFs, web pages, and internal wiki exports normalizes all three into Document objects via different loaders, letting the exact same downstream splitting, embedding, and retrieval code handle all three source types identically.
docs = pdf_loader.load() + web_loader.load() + wiki_loader.load() # all Document