Document Loaders
Document loaders read text from sources (files, URLs, databases, APIs) into LangChain Documents. The first step of every RAG pipeline: get content + metadata into a normalised shape.
File, URL, PDF, code, batch + metadata
EXAMPLE
from langchain_community.document_loaders import (
TextLoader, DirectoryLoader, PyPDFLoader, UnstructuredFileLoader,
WebBaseLoader, RecursiveUrlLoader,
GitLoader, NotionDirectoryLoader, ConfluenceLoader,
CSVLoader, JSONLoader, BSHTMLLoader,
)
from langchain_text_splitters import RecursiveCharacterTextSplitter, MarkdownHeaderTextSplitter
# 1) Plain text file
loader = TextLoader('./docs/spec.txt', encoding='utf-8')
docs = loader.load()
print(docs[0].page_content[:200])
print(docs[0].metadata) # { 'source': './docs/spec.txt' }
# 2) Directory — recursive, filtered
loader = DirectoryLoader(
'./docs',
glob='**/*.md',
loader_cls=TextLoader,
show_progress=True,
use_multithreading=True,
)
docs = loader.load()
# 3) PDFs
loader = PyPDFLoader('paper.pdf')
docs = loader.load()
# One Document per page; metadata has 'page' number
# For ranked layout + images + tables, try Unstructured:
loader = UnstructuredFileLoader('paper.pdf', mode='elements')
elements = loader.load()
# Elements have categories: 'NarrativeText', 'Title', 'ListItem', 'Table', ...
# 4) Web pages
loader = WebBaseLoader([
'https://example.com/docs/intro',
'https://example.com/docs/usage',
])
docs = loader.load()
# Crawl a whole site
loader = RecursiveUrlLoader(
url='https://example.com/docs/',
max_depth=2,
prevent_outside=True,
use_async=True,
)
docs = loader.load()
# 5) Code (Git repos)
loader = GitLoader(
clone_url='https://github.com/me/myapp.git',
repo_path='./tmp/myapp',
branch='main',
file_filter=lambda f: f.endswith(('.py', '.md', '.ts', '.go')),
)
docs = loader.load()
# 6) Notion / Confluence / Google Drive — when team docs live there
loader = NotionDirectoryLoader('./exports/notion-export')
loader = ConfluenceLoader(url='https://corp.atlassian.net/wiki', username='x', api_key='y', space_key='ENG')
# 7) CSV — one Document per row by default
loader = CSVLoader(
'./data/faqs.csv',
source_column='question',
metadata_columns=['category', 'tags'],
)
docs = loader.load()
# 8) JSON / JSONL via jq path
loader = JSONLoader(
file_path='./data/events.jsonl',
jq_schema='.message',
text_content=False,
metadata_func=lambda r, m: {**m, 'user_id': r.get('user_id'), 'ts': r.get('ts')},
)
# 9) HTML files
loader = BSHTMLLoader('./docs/page.html')
docs = loader.load()
# Or strip to main content + use Unstructured for ranked layout
# 10) Custom metadata — make retrieval smarter
for d in docs:
d.metadata.update({
'source': d.metadata.get('source', 'unknown'),
'category': 'support',
'updated': datetime.utcnow().isoformat(),
})
# 11) Splitting — chunk before embedding
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=['\n## ', '\n### ', '\n\n', '\n', '. ', ' '],
length_function=len,
add_start_index=True,
)
chunks = splitter.split_documents(docs)
# For Markdown / docs with clear hierarchy — split on headings + carry metadata:
md_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=[
('#', 'h1'), ('##', 'h2'), ('###', 'h3'),
])
header_splits = md_splitter.split_text(text)
# 12) Best practices
# - Set chunk_size by tokens not characters when you'll feed an LLM (use tiktoken).
# - Smaller chunks = more precise retrieval; bigger chunks = more context per chunk.
# - chunk_overlap of ~10-20% prevents losing concepts at boundaries.
# - Keep rich metadata (source URL, title, last updated) — show citations in your UI.
# - For binary / scanned PDFs: OCR first (pytesseract, AWS Textract).
# - For huge corpora: paginate; embed in batches; checkpoint progress.
# 13) Loader patterns by source type
# Markdown docs / README — TextLoader + DirectoryLoader + MarkdownHeaderTextSplitter
# PDFs — PyPDFLoader (fast) or Unstructured (layout-aware)
# Wiki / KB — Confluence / Notion / Slack loaders
# Code base — GitLoader + RecursiveCharacterTextSplitter with code separators
# Web docs — WebBaseLoader / RecursiveUrlLoader + bs4 parsing
# Structured data — CSVLoader / JSONLoader
# Multimodal — Unstructured ingestion + a multimodal embedding model
Why it matters
A solid loader + splitter step is 70% of RAG quality. Spend the time on metadata (source URL, title, last-updated) early — citations and freshness-based reranking depend on it.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader
docs1 = PyPDFLoader('handbook.pdf').load()
docs2 = WebBaseLoader('https://example.com/blog').load()
Try it Yourself »
Discussion
Loading…