Kustomize Build Check Action
Intelligent validation of Kustomize configurations in GitHub Actions with automatic dependency tracking and smart change detection.
The Problem
In GitOps workflows with dozens or hundreds of Kustomize overlays, pull request validation becomes a challenge:
- Manual testing is error-prone: "Did I remember to check all affected overlays?"
- Testing everything is slow:
kustomize buildon 50 directories takes time - CI fails are opaque: "Build failed somewhere, good luck finding it"
You need to know:
- Which overlays are affected by a base change?
- Did my patch break downstream configurations?
- Are all dependent overlays still valid?
Traditional approaches either test nothing (risky) or test everything (slow). Neither scales well.
The Solution
This action intelligently validates only what's affected by your changes:
- Auto-discovers all kustomization files in your repository
- Builds a dependency graph to understand base → overlay relationships
- Detects changed files via git diff against the base branch
- Tests affected kustomizations - bases and all their dependents
- Reports clear results with execution time and failure details
When you change manifests/app/base/kustomization.yaml, it automatically tests:
- The base itself
- All overlays that reference it
- Any overlays that reference those overlays (recursive)
Key Capabilities
- Smart dependency analysis: Understands multi-level overlay dependencies
- Helm support: Built-in support for
helmChartsin kustomization files - GitHub Actions integration: Outputs for downstream steps, annotations on failures
- Monorepo friendly: Specify
root-dirto validate specific subdirectories - Configurable failure behavior: Continue on error or fail fast
Quick Example
Basic Pull Request Validation
name: Validate Kustomize
on:
pull_request:
paths:
- '**/*.yaml'
- '**/*.yml'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # Required for git diff
- uses: michielvha/kustomize-build-check-action@main
with:
enable-helm: true
fail-on-error: true
base-ref: ${{ github.event.pull_request.base.sha || 'HEAD~1' }}This validates all affected configurations in every PR, catching issues before merge.
Monorepo with Multiple Apps
jobs:
validate-app1:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: michielvha/kustomize-build-check-action@main
with:
root-dir: ./apps/app1/manifests
enable-helm: true
validate-app2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: michielvha/kustomize-build-check-action@main
with:
root-dir: ./apps/app2/manifests
enable-helm: trueEach app gets independent validation with its own dependency graph. Can speed up the process when using large repositories
Continue on Error for Reporting
- name: Validate Kustomize (non-blocking)
uses: michielvha/kustomize-build-check-action@main
with:
fail-on-error: false # Don't fail the workflow
enable-helm: true
- name: Check validation results
if: always()
run: |
echo "Total builds: ${{ steps.validate.outputs.total }}"
echo "Successful: ${{ steps.validate.outputs.successful }}"
echo "Failed: ${{ steps.validate.outputs.failed }}"Use outputs to build custom reporting or notifications without blocking the pipeline.
How It Works
Dependency Graph Construction
The action discovers all kustomization files and builds a dependency graph:
manifests/
├── app/base/ [BASE]
│ └── kustomization.yaml
│ (used by dev, staging, prod)
└── app/overlays/
├── dev/ [OVERLAY]
│ └── kustomization.yaml (references: ../../base)
├── staging/ [OVERLAY]
│ └── kustomization.yaml (references: ../../base)
└── production/ [OVERLAY]
└── kustomization.yaml (references: ../../base)Graph representation:
base → [dev, staging, production]Impact Analysis
When manifests/app/base/kustomization.yaml changes:
- Detects the changed file is a kustomization
- Finds the kustomization directory:
manifests/app/base - Looks up all dependents in the graph:
[dev, staging, production] - Tests all affected:
base + dev + staging + production
Result:
✅ manifests/app/base - Build successful (0.05s)
✅ manifests/app/overlays/dev - Build successful (0.12s)
✅ manifests/app/overlays/staging - Build successful (0.11s)
✅ manifests/app/overlays/production - Build successful (0.13s)
Summary: 4 total, 4 successful, 0 failedRecursive Dependencies
Handles multi-level overlays correctly:
base → overlay1 → overlay2When base changes, tests: base, overlay1, AND overlay2 (recursive).
Configuration Reference
Inputs
| Input | Description | Default | Required |
|---|---|---|---|
enable-helm | Enable Helm chart support | true | No |
fail-on-error | Fail workflow if builds fail | true | No |
base-ref | Git ref to compare against | HEAD~1 | No |
root-dir | Directory to search for kustomizations | . | No |
Outputs
| Output | Description |
|---|---|
total | Total kustomizations tested |
successful | Number of successful builds |
failed | Number of failed builds |
Advanced Usage
Custom Base Ref for Pull Requests
with:
base-ref: ${{ github.event.pull_request.base.sha || 'HEAD~1' }}This ensures you test ALL changes in the PR, not just the last commit:
- With
base.sha: Compares entire PR branch against base (e.g.,main) - Without it (
HEAD~1): Only compares last commit against previous commit
If your PR has 3 commits that change different files, HEAD~1 would only test the last commit's changes!
Kubeconform Validation
Combine with kubeconform for schema validation:
- name: Validate Kustomize
uses: michielvha/kustomize-build-check-action@v1
with:
fail-on-error: false
id: kustomize
- name: Schema validation with kubeconform
if: steps.kustomize.outputs.failed == '0'
run: |
# Only run kubeconform if kustomize builds succeeded
for path in ${{ steps.kustomize.outputs.paths }}; do
kustomize build $path | kubeconform -strict
doneMatrix Strategy for Large Repos
strategy:
matrix:
app: [app1, app2, app3, app4]
fail-fast: false
steps:
- uses: michielvha/kustomize-build-check-action@v1
with:
root-dir: ./manifests/${{ matrix.app }}Parallel validation across multiple applications.
Why This Matters
Developer Experience
Developers shouldn't need to understand the entire dependency tree. They make a change, open a PR, and get immediate feedback on what broke.
No guessing which overlays to test manually. No waiting for production to discover the issue.
GitOps Best Practices
This action enforces validation before merge. Your main branch stays clean, and your deployments stay reliable.
Combined with Argo CD or Flux, you get a complete GitOps pipeline:
- Change manifests
- Open PR
- Automated validation (this action)
- Merge
- Auto-deploy
Architecture
The action is backed by a dual-repository architecture:
- kustomize-build-check: Go CLI tool, binaries, Docker images
- kustomize-build-check-action: GitHub Action wrapper
This separation provides:
- Clean user interface (action repo)
- Reusable tool for other CI/CD systems (tool repo)
- Container-based execution for consistency
- Independent versioning
Security
The action runs in a Docker container as a non-root user (UID 1001) matching GitHub Actions runner permissions.
Git operations use system-level safe.directory configuration to handle mounted volumes:
RUN git config --system --add safe.directory '*'No credentials are stored or transmitted. The action only needs repository read access.
