key:: value Dataview fields are silently invisible[5]. Use a type discriminator, flat keys (Properties has no nested objects[8]), reusable property names, and reserve hashtags for state — not topic[17]. New schemas in 2026 should target Bases. Dataview has stagnated[9].
YAML · book.note.frontmatter --- type: book # discriminator (Bases filter axis) title: "Foundation" author: "Isaac Asimov" # reusable across `type`s created: 2026-04-30 # Date updated: 2026-04-30T09:00 # Date & Time status: active # Text → enum tags: [scifi, classic] # List · plural mandatory ≥1.9 aliases: ["Asimov · Foundation"] # reserved · list-only related: ["[[Foundation and Empire]]"] # quoted wikilink source: https://en.wikipedia.org/wiki/Foundation_(novel) rating: 9 # Number done: false # Checkbox series_name: "Foundation" # flat keys (no nesting) series_num: 1 publish: false # selective-publish gate --- # note body — inline state tags below the YAML #status/active #priority/p2
today(), now(), file.ctime[41]; Dataview exposes .year, .month[40]..enum([...]), Pydantic str-Enum, Yamale enum().tag: no longer functions.[[X]] parses as a nested list[40].type to avoid collisions.FROM #status pulls all children[20].| Field | Type | Card. | Default | Notes | Cite |
|---|---|---|---|---|---|
| type | Text (enum) | required | — |
Single mandatory discriminator. One Base view filters per type. Reusable across categories. |
[5][13] |
| title | Text | required | file.basename |
Free string. Useful when filename is sluggified or contains an ID prefix. | — |
| created | Date | required | $today |
ISO YYYY-MM-DD. Auto-populate via Templater or Frontmatter Generator. |
[40][41] |
| updated | DateTime | optional | $now |
ISO YYYY-MM-DDTHH:mm. Use file.mtime in Bases formulas if absent. |
[41] |
| status | Text (enum) | required | "active" |
Lifecycle: active · archived · done. Validated as enum in all three lanes. |
[35][42][38] |
| tags | List<Text> | optional | [] |
Reserved. Plural form mandatory since 1.9. lowercase + singular per item. | [2][58] |
| aliases | List<Text> | optional | [] |
Reserved. Used by Wikilink autocomplete. List-only since 1.9. | [11] |
| cssclasses | List<Text> | optional | [] |
Reserved. Per-note CSS hooks. List-only since 1.9. | [4] |
| related | List<Link> | optional | [] |
Quote wikilinks: "[[Page Name]]". Bases auto-detects; Dataview type-infers. |
[40][41] |
| rating | Number | optional | null |
Integers and floats. Use Bases comparisons (≥, between) for ranking views. |
[6] |
| done | Checkbox | optional | false |
Boolean. Backed by Properties Checkbox type. | [4] |
| source | URL | optional | — |
Plain string. No native URL type — validate via Zod .url() / Pydantic HttpUrl. |
— |
| publish | Checkbox | optional | false |
Selective-publish gate (Quartz ExplicitPublish, opt-in pattern). |
— |
| {type}_* | any | optional | — |
Type-namespaced flat keys: book_status, video_status, series_name. snake_case. |
[8][13] |
| Property type | YAML | Bases surface | Dataview surface |
|---|---|---|---|
| Text | status: active |
String filters, contains, matches |
Text; substring & regex matches |
| List | tags: [a, b] |
Multi-value; contains-any |
List; .length, .contains() |
| Number | rating: 8 |
Numeric ops = > < between |
Number; arithmetic in inline DQL |
| Checkbox | done: true |
Boolean filter | Boolean |
| Date | due: 2026-05-01 |
today(), date("…"), range |
Date; .year, .month, .day |
| Date & Time | published: 2026-04-30T09:00 |
now(), file.mtime |
Date; full YYYY-MM-DDTHH:mm:ss.nnn+ZZ |
| Link (reserved) | related: "[[Page]]" |
Auto-detects wikilinks; link("…") |
Link; .path, .display |
| tags / aliases / cssclasses (reserved · list-only) | Plural form mandatory since 1.9 — singular silently no-ops [2][11]. | ||
Constraint. Once a key is typed in any note, that type is vault-wide[4]. Renaming or retyping a key after the fact is the most-cited operational pain point — see § 07.
type discriminatorseries.name, write series_name. Namespacing per-type (book_status vs video_status) prevents type collisions across note kinds[8].
| Approach | Strength | Weakness | Extraction-friendly |
|---|---|---|---|
| Folder-only PARA | Familiar; matches productivity literature | Projects/Resources collapse[19] | ✗ folder is a string |
| Johnny.Decimal | Stable addresses; pairs well with hierarchical tags[14] | Hard ceiling 100 IDs (10×10)[15] | ~ numeric prefix parseable, rigid |
| MOC (LYT) | Spawn at 5+ notes on a topic[18] | Discoverability depends on link discipline | ~ implicit unless mirrored in a property |
| Hierarchical state tags | Cross-cutting; queryable parent/child[20] | Casing/separator hygiene[21] | ✓ FROM #project pulls children |
| type discriminator + flat YAML | One Base per type[5]; the 2026 default | Up-front template work | ✓ best for Bases |
import { defineCollection, reference, z } from 'astro:content'; const notes = defineCollection({ schema: z.object({ title: z.string(), created: z.coerce.date(), tags: z.array(z.string()), status: z.enum(['active', 'archived', 'done']), author: reference('authors'), }), });
z.coerce.date() converts ISO → JS Date. reference() cross-validates wikilinks. Eleventy v3 mirrors via eleventyDataSchema[36]. astro-editor ⭐ 445 turns the same schema into a typed form[43].
from enum import Enum from pydantic import BaseModel from pydantic_yaml import parse_yaml_raw_as class Status(str, Enum): active = "active" archived = "archived" done = "done" class Note(BaseModel): title: str status: Status = Status.active tags: list[str] = []
pydantic_yaml round-trips via parse_yaml_raw_as()/to_yaml_str()[42]. Lighter alternative: Yamale ⭐ 764 ships str(), int(min,max), day(), enum(), regex(), include()[38].
# mdschema · ./schema.yaml - { name: "title", type: string } - { name: "created",type: date, format: date } - { name: "author", optional: true, format: email } - { name: "tags", optional: true, type: array }
remark-lint-frontmatter-schema validates against JSON Schema in a remark pipeline; supports per-file $schema, IDE underlining, auto-fix[37]. Stack with markdownlint-cli2 via its frontMatter regex skip[44].
| Tool | Lang | Stars | Notes |
|---|---|---|---|
| Generic frontmatter parsers | |||
| JS | ⭐ 4.4k | De-facto JS parser; YAML/JSON/TOML/Coffee + custom engines; powers Astro, Gatsby, VitePress, TinaCMS[25]. ⚠ Recent: js-yaml prototype-pollution (#178, Nov 2025); ESM/Vite SSR is not a function (#181, Feb 2026); invalid frontmatter mis-cached (#166, #174)[26]. |
|
| Py | ⭐ 412 | Pluggable handlers (YAML/JSON/TOML); v1.1.0 (Jan 2024). ⚠ BOM gotcha — open files with utf-8-sig[24]. |
|
| JS | ⭐ 320 | v5.0.0. ⚠ Recognises the fence — does not parse the YAML body. Compose with vfile-matter or remark-mdx-frontmatter[27]. |
|
| Rs | — | Rust port of jonschlinkert's; YAML/JSON/TOML + custom engines[33]. | |
| Rs | ⭐ 8 | Typed; YAML default; TOML/JSON behind cargo features for build-size control[34]. | |
| Obsidian-aware extractors | |||
| Py | ⭐ 553 | v0.11.0 (Jul 2025); wraps python-frontmatter; vault.get_front_matter, vault.get_tags, NetworkX graph; tag extractor strips code blocks & escaped \#; falls back to {} on invalid YAML[28][29]. |
|
| Rs | ⭐ 1.3k | v25.3.0 (Mar 2025); --frontmatter=always|never; --skip-tags/--only-tags. ⚠ errors on mutual [[A]]<->[[B]] embeds unless --no-recursive-embeds[30]. |
|
| Py | ⭐ 312 | Only library that round-trips between YAML and Dataview inline key:: value. ⚠ no tagged release; explicit "back up your vault" warning[31]. |
|
key:: value[32]. A frontmatter-only extractor will silently miss the inline class. If your vault uses inline fields, use obsidiantools / pyomd or run a one-time hoist into YAML.
#glue, #wood, #saw) → noise > signal.#dog, #dogs, #pets, #mammals?type) prevent collisions.Tag List note in the vault root + Auto Note Mover[46]. The canonical script: Karan Sharma's Claude-API walker that prefers existing fields over generated ones[51].
patch_content for targeted frontmatter edits[53]; MCPVault provides AST-aware YAML preservation + list_all_tags[52]; AI Knowledge Filler (Feb 2026) — system prompt that turns Claude/GPT into a deterministic vault-ready file generator[50].
Tag List note; hybrid mode prefers existing tags before suggesting new[45][46].type. Filter on the discriminator first; further refine with tags contains + numeric/date ops[6].[n] footnotes inline. Render: canonical (default) · atlas.