How to convert json to a helm chart values.yaml
- Step 1Get the JSON config — Start from a Terraform
helm_releaseset/valuesJSON, a CI-generated config object, or hand-compose the key-value structure that matches your chart'svalues.yamlschema. - Step 2Fix string-vs-number types before converting — Check your chart's
values.schema.json(or its defaultvalues.yaml). If a field likeservice.portis expected as a string but your JSON has it as a number, change it to a JSON string ("8080") now — the converter preserves JSON types exactly and won't quote a number for you. - Step 3Drop the JSON file on the tool — There's no paste field — drop the
.jsonfile. Free tier accepts up to 2 MB; Pro raises it to 100 MB, ample for any values file. - Step 4Use indent 2 and run — Leave indent at 2 for standard chart formatting (compact list items), then click Convert to YAML. Indent 4 expands every
extraEnv/tolerationsitem onto its own line — valid, but not chart-idiomatic. - Step 5Add documentation comments by hand — JSON has no comments, so the output
values.yamlhas none. Paste it into your editor and add#comments above non-obvious sections — this readability gain is a key reason to keep values in YAML rather than JSON. - Step 6Validate, then deploy — Validate against the chart's
values.schema.json(convert the YAML back to JSON with yaml-to-json and run a JSON Schema check), thenhelm upgrade my-release my-chart --values values-production.yaml, or commit for ArgoCD/Flux.
The two real conversion controls
Only these options appear in the json-to-yaml UI. Line width (80) and anchor handling are fixed.
| Control | Values | Default | Helm impact |
|---|---|---|---|
| Indent | 2 or 4 | 2 | Use 2 for compact list items (extraEnv: [- name: ...]). Indent 4 expands each - onto its own line — valid, but not how charts are written |
| Sort keys alphabetically | on / off | off (preserves order) | Off keeps your authored order matching the chart's docs. On alphabetises every map — useful for diff-stable per-environment override files |
| Line width (fixed) | 80 columns | 80 (not adjustable) | A long single-line string (e.g. a command or a long annotation value) folds with >-. Helm renders the same value; rarely an issue |
| Anchors / aliases (fixed) | disabled | noRefs = true | Repeated blocks (e.g. the same resource map reused) are written out fully — no &anchor/*alias. Helm supports YAML anchors, but writing them out keeps helm template output predictable |
Type mapping that decides helm upgrade success
The converter follows JSON types exactly. These are the cases where a chart's schema cares about string vs number.
| JSON in | YAML out | Chart note |
|---|---|---|
"port": 8080 (number) | port: 8080 (integer) | Fine if the chart wants an integer. If it wants a string, change JSON to "8080" first |
"port": "8080" (string) | port: '8080' (quoted string) | Correct for charts whose schema requires a string port |
"tag": "1.25" | tag: '1.25' | Quoted string — prevents YAML reading 1.25 as a float and dropping precision |
"enabled": true | enabled: true | Boolean — correct for ingress.enabled, autoscaling.enabled |
"extraEnv": [ {"name":"K","value":"v"} ] | extraEnv: sequence | List of maps → YAML sequence, indent 2 gives compact - name: |
"replicaCount": null | replicaCount: null | Literal null — review; charts may prefer the key omitted to use the default |
Cookbook
Real Helm config JSON converted to values.yaml. Registries and secret names are illustrative; nothing is uploaded.
Standard values.yaml from a config object
ExampleA typical chart config object converts to a clean values.yaml. Note image.tag is quoted as a string so 1.25 doesn't become the float 1.25.
JSON:
{"replicaCount":3,
"image":{"repository":"myreg/web","tag":"1.25"},
"service":{"type":"ClusterIP","port":80},
"ingress":{"enabled":true}}
YAML (indent 2):
replicaCount: 3
image:
repository: myreg/web
tag: '1.25'
service:
type: ClusterIP
port: 80
ingress:
enabled: trueThe string-port gotcha
ExampleMany charts' values.schema.json require a string port. The converter follows JSON types exactly — so you must make the port a string in the JSON. It will NOT quote a number for you.
Chart wants a STRING port.
Wrong JSON (number): {"service":{"port":8080}}
→ YAML: port: 8080 # integer — schema validation fails
Right JSON (string): {"service":{"port":"8080"}}
→ YAML: port: '8080' # string — passes the chart schemaList values: extraEnv and tolerations
ExampleArrays of maps become compact YAML sequences at indent 2 — the form Helm charts expect for extraEnv, tolerations, and imagePullSecrets.
JSON:
{"extraEnv":[{"name":"LOG_LEVEL","value":"info"}],
"imagePullSecrets":[{"name":"regcred"}]}
YAML (indent 2):
extraEnv:
- name: LOG_LEVEL
value: info
imagePullSecrets:
- name: regcredComments don't survive — add them after
ExampleJSON has no comments, so the output has none. Add # annotations by hand in your editor — the main ergonomic reason to keep values in YAML.
JSON: {"resources":{"limits":{"cpu":"500m","memory":"512Mi"}}}
YAML (as produced — no comments):
resources:
limits:
cpu: 500m
memory: 512Mi
After hand-editing:
resources:
limits:
cpu: 500m # bumped from 250m for the v2 release
memory: 512MiMerge per-environment configs first
ExampleTo roll a base config plus an environment override into one values file, merge the JSON first with json-object-merger, then convert. Or keep them separate and pass multiple --values flags to Helm.
base.json + prod.json → json-object-merger (deep merge, prod wins) → json-to-yaml (indent 2) → values-prod.yaml Alternatively, skip the merge and let Helm layer them: helm upgrade web ./chart -f values.yaml -f values-prod.yaml
Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Comments are not generated
By designJSON cannot contain comments, so there is nothing for the converter to carry over, and it adds none of its own. The output values.yaml has no # annotations. Add documentation comments by hand after conversion — this is the main readability reason to keep Helm values in YAML rather than JSON.
String port stays integer if JSON had a number
Schema mismatch riskThe converter follows JSON types exactly — it will not quote a number into a string. If your chart's values.schema.json requires a string port or version and your JSON has a number, validation fails on helm upgrade. Fix the type in the JSON ("8080") before converting.
Version float precision (1.10 → 1.1)
Precision lossIf a version is stored as a JSON number like 1.10, JSON.parse reads it as 1.1 (trailing zero dropped) before YAML sees it. Always store chart/image tags and versions as JSON strings ("1.10") so they survive as '1.10'.
Indent 4 expands list items
ExpectedAt indent 4, each extraEnv/tolerations/imagePullSecrets item is written as a bare - with the map indented beneath. Helm parses it, but it doesn't match chart conventions and may trip linters. Use indent 2.
null values left in place
PreservedJSON null becomes literal null. Many charts treat a null value differently from an omitted key (an omitted key falls through to the chart default; an explicit null may override it). Review null lines and strip ones you'd rather leave to defaults, or pre-clean with json-null-stripper.
Invalid JSON input
ErrorThe converter runs JSON.parse on the file. A trailing comma or comment throws and nothing converts. Terraform/CI output is usually strict JSON, but if you hand-edited it, fix it with json-format-fixer first.
Large integer IDs lose precision
Precision lossNumbers above 2^53 are rounded by JSON.parse before conversion. Uncommon in Helm values, but if a config carries a giant numeric ID, store it as a JSON string to keep it intact.
Duplicate keys collapse to last
Last winsIf the source JSON has the same key twice in one object, only the last survives JSON.parse — the first is silently dropped before conversion. Validate hand-merged configs with json-validator.
Anchors not emitted for repeated blocks
By designRepeated maps (e.g. the same resource block reused across two components) are written out in full — anchor generation is disabled (noRefs fixed on). Helm supports anchors, but writing blocks out keeps helm template rendering predictable and the file readable.
Empty config sections
PreservedAn empty object becomes {} and an empty array [] on one line. A chart section you intend to leave at its defaults is often better omitted entirely than written as section: {} — delete it after conversion if so.
Frequently asked questions
How do I handle ports the chart expects as strings but JSON stores as numbers?
Change the value to a string in the source JSON ("8080") before converting. The converter follows JSON types exactly — it will not quote a number into a string for you. A JSON number 8080 becomes the YAML integer 8080; a JSON string "8080" becomes the quoted YAML string '8080'. Check your chart's values.schema.json to know which it wants.
Are comments preserved or generated?
Neither — JSON has no comments to carry over, and the converter adds none. The output values.yaml is comment-free. Add # documentation comments by hand after conversion; gaining comments is a key reason to keep Helm values in YAML rather than JSON.
Why did my version 1.10 become 1.1?
Because it was stored as a JSON number. JSON.parse reads 1.10 as 1.1 (dropping the trailing zero) before the YAML stage. Always store chart and image versions as JSON strings ("1.10"), which the converter emits as the quoted '1.10'.
Can I merge multiple JSON configs into one values.yaml?
Yes — deep-merge the JSON first with json-object-merger and convert the result, so the environment override wins over the base. Alternatively, keep them as separate YAML files and let Helm layer them with multiple --values flags at deploy time.
How do I validate the generated values against the chart schema?
Convert the YAML back to JSON with yaml-to-json and run it through a JSON Schema validator against the chart's values.schema.json. This catches missing required values and type mismatches (like an integer where a string port is expected) before helm upgrade.
Which indent should I use for values.yaml?
Indent 2. It produces the compact - name: list form charts use for extraEnv, tolerations, and imagePullSecrets. Indent 4 expands each item onto its own line — valid YAML but not chart-idiomatic, and some linters flag it.
Is the chart configuration sent to JAD Apps?
No. Conversion runs entirely in your browser using js-yaml. Image registry credentials, TLS secret names, and cluster-specific endpoints never reach a JAD Apps server. The only server-side record when signed in is an anonymous run counter, with no content.
What happens to null values in the config?
JSON null becomes literal YAML null. Be careful: an explicit null can override a chart default, whereas an omitted key falls through to the default. Review null lines, and to drop them automatically, pre-clean the JSON with json-null-stripper before converting.
Does it generate YAML anchors for repeated blocks?
No. Anchor/alias generation is disabled, so repeated maps are written out in full. Helm does support anchors, but writing blocks out keeps helm template output predictable and the values file easy to read in PRs.
What's the file size limit?
Free tier accepts files up to 2 MB; Pro raises it to 100 MB. Both are far more than any values.yaml needs. The tool takes a dropped .json file — there's no paste box.
Should I sort keys in the output?
It's off by default, which keeps your values in the same order as the chart's documented defaults — easiest to compare. Turn it on for per-environment override files where alphabetical order makes diffs across values-staging.yaml / values-prod.yaml cleaner.
Can I round-trip to confirm nothing was lost?
Yes. Convert the values.yaml back to JSON with yaml-to-json and compare with json-diff. A clean diff (key order aside if you sorted) confirms every value survived the conversion.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.