Skip to main content

JSON & YAML

Volume 3 — Modern Development

You'll write both of these constantly without necessarily having learned either formally — JSON in every API payload and appsettings.json, YAML in every Azure DevOps pipeline. This chapter covers the syntax rules and, more usefully, the specific gotchas that cause real bugs in each.

1. JSON Syntax

{
"id": 42,
"employeeName": "Pete Carroll",
"status": "Pending",
"isUrgent": false,
"requestedDate": "2026-08-01",
"approver": null,
"tags": ["vacation", "planned"],
"metadata": {
"createdBy": "system",
"revisionCount": 2
}
}
RuleDetail
KeysAlways double-quoted strings — 'id' and unquoted id are both invalid
StringsDouble quotes only, no single quotes
NumbersNo quotes; no leading zeros, no trailing decimal point without a digit after it
BooleansLowercase true/false, unquoted
NullLowercase null, unquoted
Trailing commasNot allowed — a comma after the last item/property is a syntax error
CommentsNot supported at all — JSON has no comment syntax, in any form

The trailing-comma and no-comments rules are the two that trip people up most, especially coming from JavaScript, where both are tolerated in object/array literals but not in strict JSON.

2. YAML Syntax

service: roundtrip-api
environment: production
replicas: 3
autoScale: true
tags:
- api
- production
database:
host: db.internal
port: 1433
ssl: true
RuleDetail
IndentationSignificant — defines nesting, like Python. Spaces only, never tabs.
Key-valuekey: value, a space required after the colon
ListsEither - item on its own indented lines, or inline [item1, item2]
StringsUsually don't need quotes, but quote anything containing :, #, or that could be misread as another type
Comments# comment — supported, unlike JSON

3. YAML's Sharp Edges

These aren't stylistic quibbles — each one has caused real production and pipeline bugs across the industry, repeatedly, for exactly the same reasons.

Tabs are a hard error, not a style preference

service: api
replicas: 3 # tab character used for indentation — this is a parse error, not just "not preferred"

Most editors auto-convert tabs to spaces for YAML files specifically because of this — but a copy-paste from a tab-indented source can silently reintroduce the problem.

The "Norway problem" — unquoted no/yes/on/off

country: NO # parsed as the boolean `false`, not the string "NO" — this is the actual, real "Norway problem"
autoDeploy: yes # parsed as boolean `true`

YAML 1.1 (still what many parsers implement) treats yes, no, on, off, true, false — in various cases — as booleans even when unquoted and clearly intended as strings. Always quote values like country codes or anything that happens to match a boolean keyword:

country: "NO"
autoDeploy: "yes" # or restructure to avoid the ambiguity entirely

Numbers that look like they should be strings

version: 1.0 # parsed as a float, not the string "1.0" — can silently become 1 in some contexts
zipCode: 06701 # leading zero — may parse unexpectedly depending on the parser

Quote anything where the string representation itself matters, not just its numeric value.

Indentation-based nesting mistakes

database:
host: db.internal
port: 1433 # one extra space — this is now nested UNDER host, not a sibling of it

Unlike a missing brace in JSON (which usually fails loudly), a YAML indentation mistake often still parses successfully — just into a different structure than intended, silently. This is the most common source of "the pipeline ran, but the step I added never actually executed" bugs.

4. JSON vs. YAML: When to Use Which

JSONYAML
Typical useAPI request/response payloads, appsettings.jsonConfiguration files, CI/CD pipelines, Docker Compose
Human-editabilityMore verbose, more punctuationMore readable for deeply nested config, supports comments
CommentsNot supportedSupported
Ambiguity riskLow — strict, unambiguous grammarHigher — the Norway problem, tabs, indentation
Machine generationThe near-universal default for anything generated/consumed programmaticallyRare to generate programmatically; almost always hand-written

The rough rule: if a machine writes it and another machine reads it, JSON. If a human writes and maintains it directly, YAML's comments and lower punctuation overhead usually win — which is exactly why API payloads are JSON and Azure DevOps pipelines are YAML.

5. Where These Show Up Across Traxs

FileFormatNotes
appsettings.json / appsettings.Development.jsonJSON.NET configuration, environment-specific overrides
API request/response bodiesJSONEvery RoundTrip/Waypoint endpoint
azure-pipelines.yml / azure-pipelines-dev.ymlYAMLCI/CD pipeline definitions — indentation mistakes here are exactly what caused the dev/prod branch-mixing incident (TRA-195), a --branch flag on the wrong indentation level in the wrong pipeline stage
docker-compose.ymlYAMLLocal multi-container orchestration (see the Docker Compose chapter)

6. Validating Before You Commit

JSON:

cat appsettings.json | python3 -m json.tool > /dev/null && echo "valid" || echo "invalid"

YAML (via a quick Python one-liner, since a dedicated linter isn't always installed):

python3 -c "import yaml, sys; yaml.safe_load(open('azure-pipelines.yml'))" && echo "valid" || echo "invalid"

For pipeline YAML specifically, Azure DevOps also offers a "validate" option on the pipeline before running it — worth using after any indentation-sensitive edit, since a successful parse doesn't guarantee correct structure, only that it's not malformed.

7. Troubleshooting Playbook

SymptomLikely causeWhat to check
JSON parse error, "unexpected token"Trailing comma, single quotes, or a stray commentRun it through a formatter/linter; both trailing commas and comments are invalid JSON regardless of source
A YAML boolean-looking value behaves unexpectedlyNorway problem — unquoted yes/no/on/off coerced to booleanQuote the value explicitly
Pipeline step silently doesn't runIndentation nested it under the wrong parent, parsed successfully into the wrong structureDiff against a known-good version of the file; check indentation level against the intended parent key precisely
"expected <block end>, but found..." YAML errorTab character mixed into indentationSearch the file for tab characters explicitly; most editors can highlight/convert them
Config value is 1 instead of the expected "1.0"Unquoted value parsed as a number, losing the string formatQuote it explicitly if the string representation matters
appsettings value not overriding as expectedJSON merge behavior in .NET config layering not doing what was assumed (arrays don't merge, they replace)Confirm exactly which config file/layer is providing the active value at runtime

8. Quick Reference

CategoryRuleFormat
JSONKeys must be double-quotedBoth
JSONNo trailing commasJSON only
JSONNo comments supportedJSON only
YAMLSpaces only, never tabsYAML only
YAMLQuote yes/no/on/off/country codesYAML only
YAMLComments via #YAML only
Validate JSONpython3 -m json.tool
Validate YAMLpython3 -c "import yaml; yaml.safe_load(open('f.yml'))"
Use JSON forMachine-generated/consumed payloadsAPI bodies, appsettings.json
Use YAML forHuman-maintained configurationPipelines, Docker Compose

Part of the Traxs Engineering Handbook — Volume 3: Modern Development. Companion chapters in this volume: Docker Fundamentals, Docker Compose, REST APIs, Authentication & Authorization, Postman Guide.