A Unix-style pipe for filtering, mutating, and exploring streams of Kubernetes YAML manifests.
k8q reads YAML from stdin, applies transformations, and writes the result to stdout. It understands Kubernetes semantics — kind matching, API groups, workload pod templates — so you can manipulate manifests safely without breaking formatting or losing comments.
Output is automatically formatted: fields are reordered to follow Kubernetes conventions (apiVersion, kind, metadata, spec, status), and colorized when writing to a terminal.
Built on kustomize/kyaml for lossless AST-based YAML manipulation.
go install github.com/tobiash/k8q@latestFilters the stream to keep only manifests matching the given criteria. All provided criteria must match (AND semantics).
# Get all ConfigMaps
helm template my-chart | k8q get --kind ConfigMap
# Get a specific deployment by name
helm template my-chart | k8q get --kind Deployment --name my-app
# Filter by API group
helm template my-chart | k8q get --group apps
# Filter by label selector
helm template my-chart | k8q get -l app=webFilters the stream to remove manifests matching the given criteria. Manifests matching ANY provided criterion are dropped (OR semantics).
# Remove all Flux CD resources by API group
kustomize build . | k8q drop --group toolkit.fluxcd.io
# Remove resources by multiple criteria (OR)
helm template my-chart | k8q drop --group cert-manager.io --kind ConfigMap
# Use label selectors
kustomize build . | k8q drop -l 'tier in (frontend,backend)'Replaces ${VAR} references in the raw YAML stream using values from a .env file, before parsing.
# manifest.yaml contains ${DB_HOST} and ${DB_PORT}
cat manifest.yaml | k8q subst --env-file .env
# Works with multi-document streams
helm template my-chart | k8q subst --env-file production.envAdds a label to metadata.labels on matching manifests. For workload kinds (Deployment, DaemonSet, StatefulSet, Job), the label is also injected into spec.template.metadata.labels.
# Label everything
helm template my-chart | k8q label app.kubernetes.io/managed-by=k8q
# Label only Deployments
helm template my-chart | k8q label app=web --kind DeploymentAdds an annotation to metadata.annotations on matching manifests.
# Inject an annotation
kustomize build . | k8q annotate reloader.stakater.com/auto=true --kind DeploymentUpdates container images in matching manifests (Pods, Deployments, StatefulSets, DaemonSets, Jobs, CronJobs).
# Update a specific container image
helm template my-chart | k8q set-image my-app=my-registry.io/app:v2.0.0Sets metadata.namespace on matching manifests.
# Move resources from 'default' to 'production'
helm template my-chart | k8q set-namespace production --namespace defaultDeep-merges a YAML snippet into matching manifests.
# Add a nodeSelector to all StatefulSets
k8q patch 'spec: { template: { spec: { nodeSelector: { disk: ssd } } } }' --kind StatefulSetDeletes a field from matching manifests using a dot-separated path.
# Remove clusterIP from Services
k8q remove spec.clusterIP --kind ServiceUpdates spec.replicas for matching manifests.
# Scale down everything in a namespace
k8q scale 0 --namespace devModifies metadata.name by adding a prefix or suffix.
# Add a suffix to all resources
k8q rename --suffix "-v2"Compares two sets of Kubernetes manifests semantically. Resources are matched by identity (apiVersion + kind + namespace + name), so differences in document order or field ordering are ignored.
# Compare two files
k8q diff before.yaml after.yaml
# Pipe as "after", file as "before"
helm template my-chart | k8q diff --base before.yaml
# Summary mode
k8q diff before.yaml after.yaml --summaryExit codes: 0 = identical, 1 = differences found, 2+ = error.
Instead of piping YAML through stdin, you can read directly from a file:
k8q get --kind Deployment --file manifest.yaml
k8q diff --file before.yaml --file after.yamlAll commands that produce YAML or reports support --output json for machine-readable, agent-friendly output:
k8q get --kind ConfigMap --output json
k8q count --group-by-kind --output json
k8q diff before.yaml after.yaml --output json
k8q sum --output jsonJSON output follows Kubernetes API conventions:
- Lists are wrapped in a
v1/Listenvelope withapiVersion,kind, anditems - Resource references use
ObjectRef(apiVersion,kind,name,namespace) - Quantities are rendered as Kubernetes quantity strings (e.g.,
"200m","512Mi")
k8q uses semantic exit codes for reliable automation:
| Code | Meaning |
|---|---|
| 0 | Success (no differences for diff) |
| 1 | Differences found (diff only) |
| 2 | User input error (bad args, missing file, invalid config) |
The hidden describe command emits a JSON description of the CLI for agent consumption:
k8q describeThis includes all commands, flags, descriptions, idempotency, and side-effect metadata.
Starts an in-process mock Kubernetes API server that serves piped-in manifests over HTTPS. Writes a kubeconfig pointing to the server, then optionally executes a command with KUBECONFIG set. This lets cluster scanning tools connect to k8q as if it were a real cluster.
# Run kubectl against piped manifests
helm template my-chart | k8q serve -- kubectl get deployments
# Run popeye against a Helm chart
helm template my-chart | k8q serve -- popeye
# Run kubent against a Kustomize build
kustomize build . | k8q serve -- kubent --cluster
# Run trivy against manifests
cat manifests.yaml | k8q serve -- trivy k8s --context k8q
# Interactive mode — prints kubeconfig path, waits for Ctrl+C
cat manifests.yaml | k8q serveNo cluster required. Pipe in manifests, run the tool, done.
Flags:
| Flag | Shorthand | Description |
|---|---|---|
--port |
-p |
Port to bind (default: random ephemeral) |
-- |
Separator; everything after is the command to exec |
k8q exits with the child command's exit code. In interactive mode, press Ctrl+C to stop.
Analyzers provide insights about the stream. They typically terminate the pipeline by printing a report instead of YAML.
Counts matching manifests.
# Count everything
k8q count
# Count only Deployments
k8q count --kind Deployment
# Group counts by kind
k8q count --group-by-kindCalculates total CPU and Memory requests for matching manifests (looking in Pod templates). Accounts for spec.replicas.
# Sum resources for all workloads
k8q sum
# Sum resources for a specific namespace
k8q sum --namespace production
# Fail if any container is missing requests or limits
k8q sum --require-requests --require-limits
# Assert total resources are within bounds (exits 1 if exceeded)
k8q sum --max-cpu-requests 2000m --max-mem-limits 10GiBoth filtering (get, drop) and mutation commands support the same matching filters:
| Flag | Shorthand | Description |
|---|---|---|
--kind |
Kubernetes Kind (case-insensitive) | |
--name |
Resource name (exact) | |
--namespace |
-n |
Resource namespace (exact) |
--group |
-g |
API group (substring match) |
--selector |
-l |
Kubernetes label selector |
| (positional) | kind, kind/name, or api-group |
For get, label, annotate, etc., multiple criteria are combined with AND.
For drop, multiple criteria are combined with OR.
Matching is optional for mutators (they match everything by default) but required for filters.
get and drop support Kubernetes-style label selectors via the -l / --selector flag. The syntax matches kubectl:
Commands compose naturally through pipes:
# Get a deployment, labeled, in the right namespace
helm template my-chart \
| k8q get --kind Deployment --name my-app \
| k8q label app.kubernetes.io/managed-by=k8q \
| k8q set-namespace production
# Strip Flux resources, substitute env vars, and apply
kustomize build . \
| k8q drop --group toolkit.fluxcd.io \
| k8q subst --env-file .secrets \
| kubectl apply -f -yq is a general-purpose YAML processor. k8q is purpose-built for Kubernetes manifests:
- Kind-aware filtering --
k8q get --kind Deploymentknows what a Deployment is. - Label selectors --
-l app=web,env!=stagingwith full Kubernetes selector syntax. - Workload-aware labeling -- automatically propagates labels to pod templates.
- API group matching --
k8q drop --group toolkit.fluxcd.iofilters by group, not string matching. - Canonical field ordering -- output is automatically sorted: apiVersion, kind, metadata, spec, status.
- Colorized output -- syntax-highlighted YAML in the terminal, disabled when piped.
- Formatting preservation -- uses kyaml's AST, so comments survive.
| Component | Library |
|---|---|
| CLI framework | alecthomas/kong |
| YAML engine | kustomize/kyaml |
| API server | net/http + k8s.io/apimachinery (zero additional dependencies) |
| Env substitution | drone/envsubst |
To enable shell completion, add the following to your shell profile (.bashrc or .zshrc):
Bash:
source <(k8q completion -c bash)Zsh:
source <(k8q completion -c zsh)See LICENSE.