Yq Frontmatter Manipulation

Using yq to read and modify YAML frontmatter in markdown files.

yq can process YAML front matter in markdown files (Jekyll, Hugo, Obsidian) using the --front-matter flag. This is useful for batch operations across a vault or content directory.

The —front-matter Flag

Two modes are available:

ModeFlagBehavior
Process--front-matter=processModify YAML, preserve rest of file
Extract--front-matter=extractOutput only the YAML, discard content

Reading Frontmatter

Extract All Frontmatter

yq --front-matter=extract '.' pokemon.md

Read Specific Field

yq --front-matter=extract '.title' pokemon.md
yq --front-matter=extract '.tags' pokemon.md
yq --front-matter=extract '.stats.hp' pokemon.md

Check if Field Exists

yq --front-matter=extract 'has("publish")' pokemon.md
yq --front-matter=extract '.publish // false' pokemon.md

Modifying Frontmatter

Update a Field (Preserve Content)

yq --front-matter=process '.title = "Pikachu Guide"' pokemon.md

Update In-Place

yq --front-matter=process -i '.publish = true' pokemon.md
yq --front-matter=process -i '.rating = 8' pokemon.md

Add New Field

yq --front-matter=process -i '.region = "Kanto"' pokemon.md

Add to Array

yq --front-matter=process -i '.tags += ["legendary"]' pokemon.md

Delete Field

yq --front-matter=process -i 'del(.draft)' pokemon.md

Batch Operations

yq only processes the first file when given multiple arguments. Use find with -exec for batch operations:

Update All Markdown Files

find . -name "*.md" -exec yq --front-matter=process -i '.updated = now' {} \;

Set Publish to True

find ./pokemon -name "*.md" -exec yq --front-matter=process -i '.publish = true' {} \;

Add Tag to All Files

find . -name "*.md" -exec yq --front-matter=process -i '.tags += ["pokemon"]' {} \;

Update Field in Specific Directory

find ./Machine\ Learning -name "*.md" \
  -exec yq --front-matter=process -i '.category = "ml"' {} \;

Extracting Data Across Files

List All Titles

for f in *.md; do
  echo "$f: $(yq --front-matter=extract '.title' "$f")"
done

Find Files Missing a Field

for f in *.md; do
  if [ "$(yq --front-matter=extract 'has("publish")' "$f")" = "false" ]; then
    echo "Missing publish: $f"
  fi
done

List Files with publish: true

for f in *.md; do
  if [ "$(yq --front-matter=extract '.publish' "$f")" = "true" ]; then
    echo "$f"
  fi
done

Practical Examples

Add Missing Title from Filename

for f in *.md; do
  title=$(basename "$f" .md)
  if [ "$(yq --front-matter=extract 'has("title")' "$f")" = "false" ]; then
    yq --front-matter=process -i ".title = \"$title\"" "$f"
  fi
done

Standardize Date Format

find . -name "*.md" -exec yq --front-matter=process -i \
  '.created = (.created | strftime("%Y-%m-%d"))' {} \;

Convert Tags String to Array

yq --front-matter=process -i '.tags = [.tags]' pokemon.md

Merge New Fields

yq --front-matter=process -i '. *= {"region": "Kanto", "generation": 1}' pokemon.md

Handling Edge Cases

Files Without Frontmatter

yq treats the entire file as YAML if no frontmatter delimiters exist. Always use --front-matter=process for safety:

# Safe - won't corrupt files without frontmatter
find . -name "*.md" -exec yq --front-matter=process -i '.publish = true' {} \;

Empty Frontmatter

# Check for empty frontmatter
yq --front-matter=extract '. == null' file.md

Tips

  1. Always test without -i first to preview changes
  2. Use --front-matter=process to preserve markdown content
  3. Use --front-matter=extract for read-only queries
  4. Use find -exec for batch operations (not multiple file arguments)
  5. Quote field values that might contain special characters
  • Yq - General yq usage
  • Jq - Similar patterns for JSON

Resources