What is YAML — the format where Norway turns into false

There's a famous story known as "the Norway problem." Someone was listing countries in a YAML file:
countries:
- DE
- FR
- NO
Germany and France loaded as the strings "DE" and "FR". Norway loaded as false. Not the string "NO" — the literal boolean "no". Because in classic YAML, the words no, yes, on, off are ways to write true and false, and the parser dutifully read it that way.
That's YAML in a nutshell: a format that looks so simple you want to write it without rules — while it very much has rules, some with surprises. Let's learn to read it with confidence.
Where you'll meet it
YAML is the standard format for configs: settings files that a human writes and a program reads. Open almost any project on GitHub and you'll see .yml files: CI/CD settings in .github/workflows/, docker-compose.yml, deploy configs. Even the frontmatter block at the top of Markdown files is YAML.
So you won't be writing much YAML from scratch — you'll be editing existing files: bumping a version, adding a step, renaming a variable. Three building blocks cover all of that.
The three blocks every YAML is made of
The key: value pair — the foundation:
name: kodiq-app
port: 3000
debug: true
Nesting via indentation. Here's the big difference from JSON: no curly braces — what belongs inside what is shown by two spaces of indentation:
server:
host: localhost
port: 3000
host and port are shifted right — so they live "inside" server. Indentation isn't decoration here, it's syntax. Shift a line by one space and the file's meaning changes, or it fails to parse. So the rule is simple: always two spaces, never tabs (tabs are forbidden in YAML).
Lists via dashes:
steps:
- install
- build
- deploy
That's it. These three blocks are enough to read 95% of the configs you'll ever meet.
Survival rules
Four habits that cover nearly every trap:
- Quote the surprise-prone strings.
NO,yes,off, version3.10(unquoted it becomes the number3.1!), time08:30, anything with a colon inside. In doubt? Quotes never hurt:country: "NO"is always a string. - Spaces only, always two. Set your editor to insert spaces on Tab and half the problems disappear.
- A space after the colon.
port: 3000works,port:3000doesn't. - Broken and you can't see where — run it through a validator. Or paste the file into an AI assistant and ask "where's the error in this YAML" — it spots a shifted indent faster than eyes do.
About the Norway problem specifically: the modern YAML 1.2 spec treats a bare no as an honest string, but many popular parsers still follow the old rules. Don't gamble on which one you got — just use quotes.
Why not JSON, if it's stricter?
Fair question: JSON's rules are tighter, fewer surprises — why aren't configs written in it? Because JSON can't do the one thing configs need most: comments. A line like # disabled until release is impossible in JSON. For a settings file that's disqualifying — which is why the config world settled on YAML.
Fun fact: YAML is formally a superset of JSON. A valid JSON file is simultaneously valid YAML. So they're not rivals but two formats for different jobs — we sorted out which goes where in a separate comparison: JSON vs YAML.
What's the difference between .yml and .yaml?
Same format, two spellings of the extension. Officially .yaml is recommended, but many tools (GitHub Actions, for one) historically use .yml. Both work.
Why won't my YAML parse when it looks fine?
Nine times out of ten — indentation: a tab snuck in instead of spaces, or a line drifted by one space. Turn on invisible-character display in your editor or feed the file to a validator — the error shows up instantly.
Do I need to study YAML properly?
No. The three blocks from this article plus the survival rules are all a beginner needs. The rest teaches itself: every time you edit someone's config, you're already reading it.
Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.





