yq — Multi-Document
Multi-Document YAML
YAML supports multiple documents in one file, separated by ---.
This is common in Kubernetes manifests, Helm templates, and front matter.
Document Index
Access documents by index
cat <<'YAML' > /tmp/multi.yml
apiVersion: v1
kind: Namespace
metadata:
name: monad
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: monad-sa
namespace: monad
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: monad-api
namespace: monad
YAML
yq 'select(documentIndex == 0)' /tmp/multi.yml
# Output: the Namespace document only
Access the second document
cat <<'YAML' > /tmp/multi.yml
name: first
---
name: second
---
name: third
YAML
yq 'select(documentIndex == 1)' /tmp/multi.yml
# Output:
# name: second
documentIndex is zero-based. Document 0 is the first ----separated block.
Count documents in a file
cat <<'YAML' > /tmp/multi.yml
kind: Namespace
---
kind: ServiceAccount
---
kind: Deployment
---
kind: Service
YAML
yq '[documentIndex] | max + 1' /tmp/multi.yml 2>/dev/null
# Alternative: count with a shell pipeline
yq -r 'documentIndex' /tmp/multi.yml | sort -u | wc -l
# Output: 4
Selecting Documents by Content
Select Kubernetes resources by kind
cat <<'YAML' > /tmp/k8s.yml
apiVersion: v1
kind: Namespace
metadata:
name: monad
---
apiVersion: v1
kind: Service
metadata:
name: monad-svc
namespace: monad
spec:
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: monad-api
namespace: monad
YAML
yq 'select(.kind == "Service")' /tmp/k8s.yml
# Output: only the Service document
List all resource kinds in a manifest
cat <<'YAML' > /tmp/k8s.yml
kind: Namespace
---
kind: ServiceAccount
---
kind: Deployment
---
kind: Service
---
kind: Ingress
YAML
yq -r '.kind' /tmp/k8s.yml
# Output:
# Namespace
# ServiceAccount
# Deployment
# Service
# Ingress
When applied to a multi-document file, yq evaluates the expression against each document.
Select documents matching a condition
cat <<'YAML' > /tmp/k8s.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: default
---
apiVersion: v1
kind: ConfigMap
metadata:
name: db-config
namespace: monad
---
apiVersion: v1
kind: Secret
metadata:
name: db-creds
namespace: monad
YAML
yq 'select(.metadata.namespace == "monad")' /tmp/k8s.yml
# Output: both monad-namespace documents (db-config and db-creds)
Splitting Multi-Document Files
Write each document to a separate file
cat <<'YAML' > /tmp/multi.yml
kind: Namespace
metadata:
name: monad
---
kind: Deployment
metadata:
name: monad-api
---
kind: Service
metadata:
name: monad-svc
YAML
# Split by document index
for i in 0 1 2; do
yq "select(documentIndex == $i)" /tmp/multi.yml > "/tmp/doc-${i}.yml"
done
ls /tmp/doc-*.yml
# Output: /tmp/doc-0.yml /tmp/doc-1.yml /tmp/doc-2.yml
Split by resource kind
cat <<'YAML' > /tmp/k8s.yml
kind: Namespace
metadata:
name: monad
---
kind: Deployment
metadata:
name: monad-api
---
kind: Service
metadata:
name: monad-svc
YAML
for kind in Namespace Deployment Service; do
yq "select(.kind == \"$kind\")" /tmp/k8s.yml > "/tmp/${kind,,}.yml"
done
# Creates: /tmp/namespace.yml, /tmp/deployment.yml, /tmp/service.yml
Merging Documents
Concatenate YAML files into multi-document
cat <<'YAML' > /tmp/ns.yml
apiVersion: v1
kind: Namespace
metadata:
name: monad
YAML
cat <<'YAML' > /tmp/deploy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: monad-api
YAML
yq '.' /tmp/ns.yml /tmp/deploy.yml
# Output: both documents separated by ---
Passing multiple files to yq concatenates them as a multi-document stream.
Merge specific fields across documents
cat <<'YAML' > /tmp/multi.yml
kind: Deployment
metadata:
name: app-a
labels:
team: alpha
---
kind: Deployment
metadata:
name: app-b
labels:
team: beta
YAML
yq -r 'select(.kind == "Deployment") | .metadata.name + " (" + .metadata.labels.team + ")"' /tmp/multi.yml
# Output:
# app-a (alpha)
# app-b (beta)
Front Matter
Many static site generators (Hugo, Jekyll) use YAML front matter delimited by ---.
Extract front matter from a Markdown file
cat <<'EOF' > /tmp/post.md
---
title: Infrastructure Migration
date: 2026-04-11
tags:
- vyos
- migration
- network
draft: false
---
# Content here
This is the body of the post.
EOF
# yq can read the front matter as the first YAML document
sed -n '2,/^---$/p' /tmp/post.md | sed '$d' | yq '.title'
# Output: Infrastructure Migration
Extract front matter tags
cat <<'EOF' > /tmp/post.md
---
title: Infrastructure Migration
tags:
- vyos
- migration
- network
---
# Body
EOF
sed -n '2,/^---$/p' /tmp/post.md | sed '$d' | yq -r '.tags[]'
# Output:
# vyos
# migration
# network
The pattern: sed extracts the YAML block between --- delimiters, then yq parses it.
This is a common yq + sed pipeline for static site content.
Evaluating All Documents
Apply a transformation to every document
cat <<'YAML' > /tmp/multi.yml
metadata:
labels:
env: prod
---
metadata:
labels:
env: staging
---
metadata:
labels:
env: dev
YAML
yq '.metadata.labels.env = "test"' /tmp/multi.yml
# Output: all three documents now have env: test
Expressions without select() apply to every document in the stream.
Use select(documentIndex == N) when you need to target one specific document.