DevOps Tools

Kubernetes YAML Linter

Paste one or more Kubernetes manifests separated by ---. The linter checks required fields, removed or wrong apiVersions, selector and label mismatches, resource requests and limits, probes, security context, :latest images, Services that select nothing, Ingress backends and CronJob schedules.

Private by design: anything you enter is processed in your browser only. It is never uploaded to or logged on our servers. Manifests are linted locally and never sent to a cluster or API server, so Secret values stay on your machine unless you create a share link, which stores the YAML in the link itself.

Separate multiple resources with a --- line. Lints as you type.

Lint result
Paste manifests to start.

    About this Kubernetes YAML linter

    Kubernetes accepts a surprising number of manifests that later misbehave: a Deployment whose selector does not match its Pod labels is rejected outright, a Service whose selector matches nothing silently has no endpoints, and a container without resource requests can be squeezed off a busy node. This linter parses every document in a multi-document YAML file and checks each resource for structural mistakes, removed API versions and widely recommended reliability and security settings.

    Findings show the document number, resource kind and name, and the line, so you can click straight to the problem. Errors are things the API server would reject or that cannot work, such as a removed apiVersion, a selector mismatch, an unquoted number in an environment variable or an invalid CronJob schedule. Warnings cover security and reliability: privileged containers, privilege escalation, running as root, host namespaces, hostPath volumes, missing resource requests and :latest images. Info items are suggestions such as single-replica Deployments or missing liveness probes.

    The checks are static and work offline. They do not know which Custom Resource Definitions or admission policies your cluster has, so custom kinds only get the generic checks (apiVersion, kind and a valid name). Before applying, confirm against your real cluster with kubectl apply --dry-run=server -f file.yaml, or validate against the official JSON schemas in CI with kubeconform.

    Templating with Helm? Compare and merge chart values with the Helm values tool. Running containers locally first? Check the image with the Dockerfile linter and your local stack with the Docker Compose validator. To turn a manifest into JSON for kubectl patch or jq, use the data format converter, and test CronJob schedules with the cron expression builder.

    Reference Guide

    Current apiVersion for common kinds, and versions that have been removed:

    KindUseRemoved versions
    Pod, Service, ConfigMap, Secret, Namespace, PersistentVolumeClaim, ServiceAccountv1–
    Deployment, StatefulSet, DaemonSet, ReplicaSetapps/v1extensions/v1beta1, apps/v1beta1, apps/v1beta2 (removed in 1.16)
    Ingress, IngressClassnetworking.k8s.io/v1extensions/v1beta1, networking.k8s.io/v1beta1 (1.22)
    NetworkPolicynetworking.k8s.io/v1extensions/v1beta1 (1.16)
    Job, CronJobbatch/v1CronJob batch/v1beta1 (1.25)
    HorizontalPodAutoscalerautoscaling/v2autoscaling/v2beta1 (1.25), autoscaling/v2beta2 (1.26)
    PodDisruptionBudgetpolicy/v1policy/v1beta1 (1.25)
    Role, ClusterRole, RoleBinding, ClusterRoleBindingrbac.authorization.k8s.io/v1rbac.authorization.k8s.io/v1beta1 (1.22)
    CustomResourceDefinitionapiextensions.k8s.io/v1apiextensions.k8s.io/v1beta1 (1.22)

    Required fields:

    ResourceMust have
    Every objectapiVersion, kind, metadata.name (or generateName); most names allow lowercase letters, digits, - and ., while Service and Namespace names cannot contain dots
    Deployment, StatefulSet, DaemonSet, ReplicaSetspec.selector whose labels match spec.template.metadata.labels; at least one container with name and image
    Job, CronJobrestartPolicy: Never or OnFailure in the Pod template; CronJob needs schedule and jobTemplate
    Servicespec.ports (except type: ExternalName); a selector unless you manage endpoints yourself
    Ingress (networking.k8s.io/v1)pathType on every path and backend.service.name + backend.service.port
    Labels, annotations, ConfigMap data, env valuesString values. Quote numbers and booleans: value: "8080", enabled: "true"

    Security context best practices (the Pod Security Standards "restricted" profile):

    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: app
          image: registry.example.com/app:1.4.2
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits: { memory: 256Mi }
    • Avoid privileged: true, hostNetwork, hostPID, hostIPC and hostPath volumes unless the workload is a node agent that truly needs them.
    • Set memory limits to protect the node. Many teams leave CPU limits off to avoid throttling and rely on CPU requests for scheduling.
    • readinessProbe controls whether a Pod receives Service traffic; livenessProbe restarts a stuck container. Do not point liveness at dependencies such as the database.

    Validate against a cluster: kubectl apply --dry-run=server -f manifests.yaml runs the real API validation and admission webhooks without saving anything. Offline, kubeconform -strict -summary manifests.yaml checks against the Kubernetes JSON schemas, and kubectl explain deployment.spec.template.spec documents every field.

    Example input

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: web
      template:
        metadata:
          labels:
            app: frontend
        spec:
          containers:
            - name: web
              image: nginx:latest
              env:
                - name: WORKERS
                  value: 4
              securityContext:
                privileged: true
    ---
    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: cleanup
    spec:
      schedule: "0 25 * * *"
      ...

    This sample loads automatically when you open the tool. Use Load Sample to bring it back.

    Frequently Asked Questions

    It checks each manifest for required fields, removed or deprecated API versions, selectors that do not match pod labels, missing resource requests and limits, missing probes, latest image tags and insecure security context settings.

    Yes. Paste multiple documents separated by --- and each one is checked, with findings labelled by document and line.

    No. Values under data are only Base64 encoded, which anyone can decode. Keep Secret manifests out of Git or use a tool such as Sealed Secrets or an external secrets manager.