← Back to blog

Kubernetes YAML Validation: Server Dry Runs Catch What Linters Miss

October 15, 2026
Kubernetes YAML Validation: Server Dry Runs Catch What Linters Miss

A reliable way to validate Kubernetes YAML is a workflow: lint the file locally for syntax errors, run a schema-aware validator like kubeconform against your cluster's OpenAPI definitions, then confirm it with a server-side dry-run before you ever run kubectl apply for real. Each step catches a different class of mistake, and skipping the server-side step is where most bad deploys slip through.


TL;DR:

  • Start with yamllint for syntax, then use kubeconform or kubeval against matching OpenAPI or CRD schemas; schema checks cannot fix invalid YAML.
  • Since Kubernetes 1.27, server side field validation has been generally available; only a server side dry run reveals defaults and mutations from admission webhooks.
  • For custom resources, validate against current cluster schemas because stale local CRD definitions can create false confidence, and some checks run only in cluster.
  • In CI, run yamllint and kubeconform on every pull request, use the target cluster’s schema, and block errors while reporting style warnings.
  • Admission webhooks that depend on live cluster state can make dry runs incomplete, so test those manifests in a disposable cluster or canary namespace first.

Kubezilla Desktop
Manage Clusters Without Tab Juggling
Kubezilla Desktop brings multiple clusters, live logs, metrics, Helm, and ArgoCD operations into one interface for Kubernetes workflows.
Explore Kubezilla Desktop

Table of Contents

Which validators catch which errors?

Each tool in the Kubernetes YAML validation stack checks something different, and picking the right one for the job saves you from chasing the wrong kind of error.

  • YAML linters like yamllint catch syntax problems: bad indentation, missing colons, tabs mixed with spaces, duplicate keys. They know nothing about Kubernetes schemas.
  • kubeconform and kubeval validate manifests against Kubernetes OpenAPI or CRD schemas, flagging unknown fields, wrong types, and missing required properties.
  • kubectl explain pulls field documentation straight from your cluster's API, which makes it the fastest way to confirm what a field expects and whether it is required, using --recursive and --max-depth to explore nested structures according to Harness documentation on dry-run validation.
  • Online validators in the ValidKube style bundle several checks behind a paste box, which is convenient for a one-off manifest but not a substitute for CI or a real dry-run.

Run yamllint first because it is instant and catches the dumbest mistakes before you waste time on anything smarter. Follow with kubeconform or kubeval once the YAML parses cleanly, since schema checks are pointless on a file that is not valid YAML in the first place. Use kubectl explain whenever you are unsure whether a field belongs under spec.template.spec or one level up, rather than guessing from memory or an outdated blog post. Treat browser-based validators as a quick sanity check for a single file you are pasting in, not as part of your actual release process. None of these tools talks to your live cluster's admission chain, which is exactly the gap the next section covers.

Client-side vs. server-side validation: why the server wins

Client-side validators have a structural weakness: they used to rely on OpenAPI v2, which could not fully describe custom resource schemas. That forced validators to be lenient with CRDs, which meant real errors sometimes slipped through as false negatives.

Kubernetes closed much of that gap in version 1.27, when server-side field validation reached general availability, giving the API server itself the job of validating create, update, and patch requests with more accurate error reporting. OpenAPI v3 is lossless for CRD schemas, so combined with server-side validation it closes the accuracy gap that client-only checks always had.

A few behaviors are worth knowing before you rely on this:

  • In strict mode, kubectl skips its own client-side validation and defers to the server, which is now the more trustworthy check.
  • Field validation offers modes for rejecting unknown fields, flagging them while allowing them, or skipping validation.
  • Defaulting and admission webhooks only run server-side, so a dry-run against the real API server is the only way to see the actual final object.

If your manifest depends on a mutating webhook or a default value injected by an admission controller, no local tool will show you that outcome. Only a server-side check will.

The pre-apply checklist: commands in order

Run these in sequence, and stop at the first failure since later checks assume earlier ones already passed.

  1. Lint the YAML syntax. Run yamllint deployment.yaml and fix anything it flags, typically bad indentation, tabs, or duplicate keys, before moving on.
  2. Validate against the schema. Run kubeconform -summary deployment.yaml or kubeval deployment.yaml against your cluster's OpenAPI or CRD schema files. An "unknown field" error means you typed something that does not exist; a "missing required" error means the resource is incomplete.
  3. Dry-run against the server. Run kubectl apply --dry-run=server -f deployment.yaml (or kubectl create --dry-run=server) so the request passes through defaulting and admission without being persisted, exactly as described in the Kubernetes documentation on apiserver dry-run.
  4. Review the diff. Run kubectl diff -f deployment.yaml to see precisely what the server would change on an existing object before you commit to to apply.
  5. Confirm CRD-specific checks server-side. Some validation for custom resources only happens inside the cluster, so validate against the live OpenAPI or the CRD's own schema rather than a stale local copy.
  6. Canary it if webhooks are involved. When admission webhooks depend on live cluster state, apply to a disposable test cluster or a canary namespace first rather than trusting a dry-run alone.

Pro Tip: Keep a local copy of your cluster's OpenAPI schema refreshed weekly so kubeconform checks stay accurate as CRDs change.

Building validation into your CI pipeline

Manual checks work for one file on your laptop, but a team shipping manifests daily needs validation that runs automatically on every pull request.

  • Run yamllint and kubeconform as pre-merge checks so obvious syntax and schema mistakes never reach a reviewer's attention.
  • Where your infrastructure allows it, run a server-side dry-run against a disposable test cluster in CI to catch admission and webhook issues before merge.
  • Apply a fail-fast policy: block merges on syntax and schema errors, but let style or hygiene warnings pass with a visible note instead of blocking the pipeline.
  • Fetch the exact cluster's OpenAPI or CRD bundle during the CI run, or store it securely as a versioned artifact, so you validate against the schema your manifests will actually hit in production.

Pro Tip: Pin your CI's kubeconform version and schema bundle together, so a tooling update never silently changes what counts as valid.

Surface failures directly in the pull request as inline comments or a summary check, rather than burying them in a build log nobody opens until the deploy already broke.

Getting the balance right between speed and safety

Getting the balance right between speed and safety — overview diagram

Treat server-side validation as the source of truth and local tools as the fast feedback loop that keeps you from wasting a CI run on a typo. A reasonable daily routine looks like: lint on save, run kubeconform before you commit, and let the server-side dry-run run in CI or right before a production apply.

Working across several clusters makes this harder to keep straight, since schemas and installed CRDs can differ between them. Centralizing kubeconfig access and cluster inspection in one place, which is the approach we take with Kubezilla Desktop, cuts down the friction of switching contexts mid-check.

— Margus

Validate faster without juggling five terminal tabs

We built Kubezilla Desktop around the problem this guide just walked through: validation only works when you can actually see what the cluster thinks, fast, across every environment you touch.

Kubezilla Desktop

  • We keep your kubeconfigs stored locally, so switching between clusters to compare OpenAPI schemas or run a dry-run against a staging environment is straightforward.
  • We give you a built-in YAML editor and live cluster inspection in one window, so running kubectl explain on a field or checking a live default no longer means jumping between a terminal and three browser tabs.

If validation cycles are eating your afternoon, try Kubezilla Desktop and see how much faster the checklist above runs when everything lives in one app; current prices are on our pricing page.

FAQ

What is the difference between YAML syntax validation and schema validation?

Syntax validation checks that a file is well-formed YAML: correct indentation, no duplicate keys, no broken structure. Schema validation goes further and checks whether the content matches what Kubernetes actually expects for that resource type, catching unknown or missing fields that a syntax check would miss entirely.

Client-side validators relied on OpenAPI v2, which could not fully describe custom resource schemas, so they had to be lenient and sometimes missed real errors. Server-side field validation reached general availability in Kubernetes 1.27, pairing with OpenAPI v3's lossless CRD schemas to give far more accurate error reporting straight from the API server.

How do I validate custom resources (CRDs) before applying them?

Client-side tools can check CRDs against a local schema file, but the most reliable method is a server-side dry-run, since some validation logic only runs inside the live API server. Keep your local CRD schema copies updated as your cluster's custom resource definitions evolve, since a stale schema will produce false confidence.

Can I rely only on an online YAML validator?

An online validator is fine for a quick syntax or schema check on a single file you are pasting in. It cannot run a server-side dry-run against your actual cluster, so it should never replace CI checks or a pre-apply dry-run for anything going to production.

What does kubectl diff actually show me?

kubectl diff sends your manifest through the server's defaulting and admission chain without persisting it, then shows you exactly what would change on the live object, as described in the Kubernetes blog on apiserver dry-run. It is the clearest way to see mutations, like injected defaults or admission-added fields, before you commit to an apply.

Sources