Where the term comes from, and what's actually relevant when frontmatter is used as a metadata carrier for chunking and indexing documents in a vector database.
Front matter is only one of three parts a book is traditionally divided into — for context:
When indexing for a vector database, a document is typically split into chunks, each chunk is embedded, and stored together with a metadata object. Frontmatter is the usual place where this metadata is declared in the source document itself — usually as a YAML block at the start of the file — instead of guessing it at runtime or deriving it from the file system.
The advantage: the metadata travels with the document, is versionable (e.g. in Git), human-readable, and can be carried over 1:1 into the vector record's metadata field during ingestion — regardless of whether Pinecone, Weaviate, Qdrant, Chroma, or pgvector serves as the backend.
--- title: "Enterprise Customer SLA Policy" doc_id: "kb-2026-0341" source: "confluence://legal-space/sla-policy" version: "3.2" created_at: 2025-11-04 updated_at: 2026-07-19 author: "j.doe@example-corp.com" language: "en" category: "legal" tags: ["sla", "enterprise", "support"] access_level: "internal" --- Content of the document, which is subsequently chunked and embedded …
In Markdown, frontmatter is purely a community-convention trick: free text that nobody mandates. Other file formats solve the same underlying need — carrying metadata independently of the visible content — through their own, sometimes even standardized, mechanisms.
In Word and PowerPoint (both in OOXML format, technically a ZIP container), the metadata lives in two internal XML files: docProps/core.xml and docProps/app.xml. Interestingly, the core properties are explicitly mapped to Dublin Core — the dc: prefix shows up there 1:1 (dc:title, dc:creator, dc:subject, dcterms:created). The user sets these fields via File → Info → Properties — but there's no automatically inserted cover page or table in the document itself; visible cover sheets with metadata fields are always manually designed templates. Freely definable extra fields (the equivalent of category or access_level) can be added via Advanced Properties → Custom.
PDFs have two parallel layers: the older Info Dictionary (Title, Author, Subject, Keywords) and XMP metadata — an embedded XML package, again based on Dublin Core.
With email, the analogy is most direct: RFC 5322 mandates a header block before a blank line, ahead of the actual body — From, To, Subject, Date, Message-ID, References. Structurally almost identical to YAML frontmatter, just without the --- delimiter. Part of it is set by the user (subject, recipient), part automatically by the mail client (date, message ID).
| Format | Where the metadata lives | How it's set |
|---|---|---|
| Markdown (.md) | YAML block at the start of the file | User writes the block directly as text |
| Word / PowerPoint (.docx / .pptx) |
docProps/core.xml + app.xml inside the OOXML container (Dublin Core fields) |
User via the Properties dialog; freely definable fields via "Custom" |
| Info Dictionary + embedded XMP metadata package | Set by the authoring application on export, editable afterwards with tools (Acrobat, ExifTool) | |
| Email (.eml) | RFC 5322 header block before a blank line | Partly the user (subject, recipient), partly automatic via the mail client (date, message ID) |
For the indexing pipeline, this means: for Office formats, PDFs, and emails, the parser (e.g. python-docx, python-pptx, extract-msg, Unstructured, LlamaParse, Microsoft markitdown) extracts the native metadata automatically — you don't need your own frontmatter for that. What these formats don't bring natively — category, access_level, department in the sense your pipeline needs — you still have to supply separately, e.g. via "Custom Properties" in Office files or a separate mapping table per source/folder.
| Field | Purpose | Origin |
|---|---|---|
| doc_id / origin_id | Unique ID of the source document (usually a UUID) — for updates, re-indexing, deletion | System |
| source / source_uri | Path or URI to the original source (file system, Confluence, S3, web URL) | System |
| filename | Original file name, independent of the internal storage path | System |
| origin | Ingestion channel, e.g. file-upload, web-crawler, confluence-sync | System |
| content_hash / checksum | Hash of the content for deduplication and change detection (re-embedding only on diff) | System |
| Field | Purpose | Origin |
|---|---|---|
| chunk_id | Unique ID of the individual chunk, often {doc_id}_{index} | Chunking |
| chunk_index / total_chunks | Position within the document, e.g. "chunk 20 of 181" — enables neighbor retrieval | Chunking |
| section / heading | Heading of the section the chunk comes from (improves citability) | Chunking |
| page_number | Page number for PDFs — important for exact source citations | Chunking |
| start_char / end_char | Offset in the original text, for highlighting or reassembly | Chunking |
This group deliberately doesn't belong in the frontmatter: it depends on the chosen chunk size and overlap strategy and only exists once the chunker has run — the values can change with every re-indexing run.
| Field | Purpose | Origin |
|---|---|---|
| created_at / updated_at | Creation or last-modified date of the source — for temporal filtering ("only the current version") | User |
| ingested_at | Timestamp of indexing into the vector DB (independent of the document date) | System |
| version | Document version, relevant when multiple versions can exist in parallel | User |
| embedding_model | Which embedding model was used — important when switching or migrating models | System |
| Field | Purpose | Origin |
|---|---|---|
| category / type | Rough classification, e.g. policy, ops, legal | User |
| tags[] | Freely assignable keywords for fine-grained filtering | User |
| department / owner | Organizational assignment, supports multi-tenant separation | User |
| access_level / acl | Permission level (e.g. public, internal, confidential) — essential so search doesn't return content the requesting user isn't authorized to see | User |
| language | Language code — relevant for multilingual corpora and language-specific embedding models | User |
dc: prefix is an XML/RDF namespace (http://purl.org/dc/elements/1.1/), needed only in XML/RDF serializations like RSS/Atom, OAI-PMH, or XMP metadata in PDFs. In a flat JSON metadata object for a vector DB, the prefix is dropped — only the conceptual level carries over, not the notation:chunk_id, section). Without this inheritance, you lose the link back to the source after chunking.department = "support"), before the expensive similarity computation runs.snake_case for field names. A consistent naming convention across all sources makes later filter queries considerably easier.Document.metadata) and LlamaIndex (Node.metadata) deliberately allow free-form dicts. In practice, though, almost all pipelines converge on the same core set: source, doc_id, chunk_id, created_at/updated_at, category/tags.