Schema Validation for FluxCD HelmRelease Files

Bring LSP-powered autocomplete and validation to your FluxCD HelmRelease YAML files by creating composite JSON schemas that validate both the release structure and your Helm chart values.

If you’re using FluxCD to manage Helm releases, you’ve likely debugged a failed deployment caused by a typo in your values block. Maybe you wrote replicas instead of replicaCount, or nested an option one level too deep. These mistakes are easy to make and hard to catch-often you don’t discover them until Flux fails to reconcile.

The fix? Bring the same LSP-powered autocomplete and validation you use for application code to your HelmRelease files.

The Problem with HelmRelease Values

A typical FluxCD HelmRelease looks like this:

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: my-app
  namespace: default
spec:
  interval: 5m
  chart:
    spec:
      chart: my-chart
      sourceRef:
        kind: HelmRepository
        name: my-repo
  values:
    replicaCount: 3
    image:
      repository: myapp
      tag: v1.2.3
    resources:
      limits:
        memory: 512Mi

Your editor validates the HelmRelease structure — apiVersion, kind, spec.chart, but treats the values block as an opaque blob. No autocomplete, no type checking, no validation.

If your chart includes a values.schema.json, FluxCD will fail the reconciliation when values don’t match1—a useful guardrail, but one you only discover at deploy time. The setup below brings that same validation into your editor, so you catch errors as you type.

The Solution: Composite JSON Schemas

Create a JSON schema that combines the FluxCD HelmRelease structure with your chart’s values schema, then configure your editor’s YAML language server to use it.

What we need:

  1. A JSON schema for your Helm chart’s values
  2. A template schema for the HelmRelease wrapper
  3. A way to combine them so values references your chart’s schema
  4. Editor configuration to apply the right schema to each file

Step 1: Get Your Helm Chart Schema

For Local Charts

If your chart doesn’t include a values.schema.json, generate one with helm-schema-gen:

$ helm plugin install https://github.com/rhoat/helm-schema-gen.git
$ helm schema-gen generate ./values.yaml --destination values.schema.json

Generated schemas will need refinement. Add enum constraints for limited values, mark required fields, and add descriptions for better autocomplete. A JSON Schema field can have both a $ref and local constraints like type or enum, letting you layer chart-specific restrictions on top of Kubernetes definitions.

For Remote Charts

When using charts from external repositories (cert-manager, Argo CD, etc.), you’ll need to extract or generate the schema locally.

If the chart includes a schema, pull it down:

$ helm repo add jetstack https://charts.jetstack.io
$ helm pull jetstack/cert-manager --untar --destination ./vendor-charts
$ ls ./vendor-charts/cert-manager/values.schema.json

If the chart lacks a schema, generate one from its default values:

$ helm repo add argo https://argoproj.github.io/argo-helm
$ helm show values argo/argo-cd > ./vendor-charts/argo-cd-values.yaml
$ helm schema-gen generate ./vendor-charts/argo-cd-values.yaml \
    --destination ./vendor-charts/argo-cd.schema.json

Step 2: Create the Composite Schema

The HelmRelease schema’s spec.values field references your chart’s schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["apiVersion", "kind", "metadata", "spec"],
  "properties": {
    "apiVersion": {
      "type": "string",
      "enum": ["helm.toolkit.fluxcd.io/v2", "helm.toolkit.fluxcd.io/v2beta1", "helm.toolkit.fluxcd.io/v2beta2"]
    },
    "kind": {
      "const": "HelmRelease"
    },
    "metadata": {
      "type": "object",
      "required": ["name"],
      "properties": {
        "name": { "type": "string" },
        "namespace": { "type": "string" }
      }
    },
    "spec": {
      "type": "object",
      "required": ["chart"],
      "properties": {
        "chart": { /* ... chart spec ... */ },
        "interval": {
          "type": "string",
          "pattern": "^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$",
          "default": "5m"
        },
        "values": {
          "$ref": "file:///path/to/your/chart/values.schema.json",
          "description": "Helm chart values"
        }
      }
    }
  }
}

The $ref for values points to your chart’s schema, enabling validation and autocomplete.

Step 3 (Optional): Automate with a Makefile

Skip this if you’re only dealing with one chart. But if you’re managing multiple charts, or just prefer not to repeat yourself - a Makefile keeps schema generation consistent:

# Configuration
CHARTS_DIR := ./charts
FLUX_SCHEMAS_DIR := ./flux-schemas
TEMPLATE_FILE := $(FLUX_SCHEMAS_DIR)/.helmrelease-template.json

# Find all chart directories with schemas
CHART_DIRS := $(shell find $(CHARTS_DIR) -name "values.schema.json" -exec dirname {} \;)

# HelmRelease template with CHART_SCHEMA_REF placeholder
define TEMPLATE_CONTENT
{
  "$$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["apiVersion", "kind", "metadata", "spec"],
  "properties": {
    "apiVersion": {
      "type": "string",
      "enum": ["helm.toolkit.fluxcd.io/v2", "helm.toolkit.fluxcd.io/v2beta1", "helm.toolkit.fluxcd.io/v2beta2"]
    },
    "kind": { "const": "HelmRelease" },
    "metadata": {
      "type": "object",
      "required": ["name"],
      "properties": {
        "name": { "type": "string" },
        "namespace": { "type": "string" }
      }
    },
    "spec": {
      "type": "object",
      "required": ["chart"],
      "properties": {
        "interval": {
          "type": "string",
          "pattern": "^([0-9]+(\\\\.[0-9]+)?(ms|s|m|h))+$$"
        },
        "values": { "$$ref": "CHART_SCHEMA_REF" }
      }
    }
  }
}
endef
export TEMPLATE_CONTENT

.PHONY: all clean generate-composite-schemas

all: generate-composite-schemas

$(FLUX_SCHEMAS_DIR):
	@mkdir -p $(FLUX_SCHEMAS_DIR)

$(TEMPLATE_FILE): $(FLUX_SCHEMAS_DIR)
	@echo "Creating HelmRelease template..."
	@echo "$$TEMPLATE_CONTENT" > $(TEMPLATE_FILE)

generate-composite-schemas: $(TEMPLATE_FILE)
	@echo "Generating composite schemas..."
	@for chart_dir in $(CHART_DIRS); do \
		chart_name=$$(basename $$chart_dir); \
		values_schema_path="$$chart_dir/values.schema.json"; \
		composite_schema_path="$(FLUX_SCHEMAS_DIR)/$$chart_name-helmrelease.schema.json"; \
		if [ -f "$$values_schema_path" ]; then \
			echo "  - Generating $$chart_name-helmrelease.schema.json"; \
			abs_values_schema_path=$$(realpath "$$values_schema_path"); \
			sed "s|CHART_SCHEMA_REF|file://$$abs_values_schema_path|g" \
				$(TEMPLATE_FILE) > "$$composite_schema_path"; \
		fi; \
	done
	@rm -f $(TEMPLATE_FILE)

clean:
	rm -rf $(FLUX_SCHEMAS_DIR)/*.schema.json

Running make generate-composite-schemas scans your charts directory and generates <chart-name>-helmrelease.schema.json for each chart with a values schema.

Step 4: Configure Your Editor

Tell your YAML language server which schema to use. Example for Helix (my editor of choice):

# ~/.config/helix/languages.toml

[[language]]
name = "yaml"
file-types = ["yaml", "yml"]
language-servers = ["yaml-language-server"]

[language-server.yaml-language-server.config.yaml]
completion = true
validation = true
hover = true
schemaStore.enable = true

[language-server.yaml-language-server.config.yaml.schemas]
"file:///path/to/flux-schemas/myapp-helmrelease.schema.json" = [
  "**/myapp/**/helmrelease*.yaml",
  "**/helmrelease*myapp*.yaml"
]

VS Code, Neovim, and other editors using yaml-language-server have similar configuration. Match the glob patterns to your file organization.

Helix editor showing schema validation error
Helix catches the typo: "Property installCRD is not allowed"
VS Code showing schema validation error
VS Code highlights the invalid property with the same schema

The Payoff

Once configured, your editor will:

  • Autocomplete values — Suggestions from your chart’s schema with descriptions and defaults
  • Validate as you type — Misspelled keys, wrong types, and missing fields caught immediately
  • Show documentation on hover — Field descriptions, types, and allowed values
  • Catch structural errors — Invalid interval formats, missing sourceRef, etc.

Conclusion

This setup takes about an hour initially but prevents deployment failures that consume entire afternoons. Autocomplete and real-time validation make HelmRelease authoring feel as fluid as writing code in a proper IDE.

The investment pays off most when managing multiple environments, working with a team, or using complex charts. Your future self will thank you.


  1. FluxCD helm-controller validates values against the chart’s JSON Schema during install and upgrade. Disable with spec.[install|upgrade].disableSchemaValidation. See the HelmRelease API reference↩︎