Engineering

Changelog file formats: JSON, YAML, or just Markdown

5 min read

Most teams start a changelog as a Markdown file because it is the path of least resistance: readable in a pull request diff, readable on GitHub without rendering anything, and familiar to anyone who has ever written a README. That choice works fine right up until something other than a human needs to read the file, a page, a widget, an email digest, and then the format stops being free. Changelog automation covers the structural requirement in general, a type, a date, a body and a link; this is about which file format actually delivers that structure and what each one costs to get there.

What’s wrong with a plain Markdown changelog file?

Nothing, until something needs to parse it back into fields. A heading, a date, and a bulleted list under it is trivial for a person to read and genuinely hard to parse reliably, because Markdown has no schema: the date might be in the heading, in bold text on the first line, or missing entirely on an old entry, and every one of those variations is valid Markdown that a human reads correctly and a parser doesn’t. Teams that automate a Markdown changelog usually end up writing a bespoke regex-based parser that breaks the first time an entry’s formatting drifts even slightly, which is often, because nothing enforces consistency at write time.

What does a structured format actually buy you?

A guarantee that every entry has the same shape, checked when the entry is written rather than guessed when it’s read. A JSON or YAML file with a defined schema, type, date, version, audience, body, link, fails loudly if a required field is missing, the same way a strict API response would; a Markdown file just renders whatever is there, correct or not. That difference is invisible until the day a script needs every entry’s date to sort a feed, and half the entries have it in a different place.

# CHANGELOG.yml
- date: 2026-09-05
  type: breaking
  version: v2
  audience: api
  body: "POST /invoices now rejects a currency mismatch instead of silently converting."
  link: /blog/api-changelog/

Does that mean the human-readable file has to go away?

No, and trying to make a YAML or JSON file double as the thing a person reads in a pull request is usually a mistake in the other direction: reviewing a diff of nested JSON is worse than reviewing a sentence of prose, and a reviewer who has to mentally parse a data structure to catch a wording error is a reviewer who will eventually stop catching wording errors. The two formats can coexist: structured data is the source of truth an automation pipeline reads, and a generated Markdown or HTML rendering is what a person actually reviews and reads, produced from the structured file rather than maintained by hand alongside it.

FormatHuman-readable as-isMachine-parseable without custom codeCommon failure mode
MarkdownYesNoInconsistent entry shape breaks naive parsers
JSONPoorYesVerbose, easy to hand-edit into invalid JSON
YAMLFairYesWhitespace-sensitive; a bad indent is a silent parse error, not a loud one

Which structured format is actually easier to hand-edit, JSON or YAML?

YAML, for anyone who is writing entries by hand rather than through a generator, because it drops the quoting and bracket-matching JSON requires for every string and nested object. The tradeoff is that YAML’s whitespace sensitivity fails silently in a way JSON’s bracket mismatches usually don’t: a JSON parser rejects malformed input outright, while a YAML parser can accept a badly indented file and simply parse it into the wrong structure, which is a worse failure because nothing tells you it happened. If entries are only ever written by a script, this tradeoff mostly disappears and JSON’s stricter parsing becomes the safer default.

Does a changelog page need its own structured format, separate from the file that feeds it?

Not a separate one, the same one rendered differently. A changelog page covers making the page itself machine readable through a JSON feed and schema.org markup; that feed is generated output, not a second source of truth to keep in sync with the underlying file. Maintaining structured data by hand in two places, a source file and a page’s feed, is how the two drift, so the file format decision made here should be the one thing everything downstream, page, widget, email, generates from, never hand-copies.

Is switching an existing Markdown changelog to a structured format worth the migration cost?

Usually only once automation is the actual goal, not before. A one-person project publishing a Markdown file to a GitHub README has no real automation need, and converting it to YAML buys nothing but ceremony. The conversion pays for itself the moment more than one downstream consumer, a page, a digest email, a public feed, needs to read the same data, because that is exactly the point where a Markdown parser’s inconsistencies start producing visibly wrong output instead of just being annoying to maintain.

FAQ

Can a Markdown changelog be made parseable without switching formats entirely? Partially, with frontmatter: a small YAML block at the top of each entry (date, type, version) next to a Markdown body for the prose. This gets the structured fields a parser needs without forcing the whole entry into JSON or YAML, and it is a reasonable middle ground for a team not ready for a full migration.

Does the file format matter for SEO or for how a changelog page ranks? Not directly. Search engines read the rendered page, not the source file, so the file format is invisible to them; what matters for the page itself is whether it is machine readable in its own right, which is a separate concern from what generates it.

Should every changelog entry go through the same file, or can types be split across files? One file is simpler until entry volume makes it unwieldy to diff or review; splitting by year or by category is a reasonable relief valve once a single file’s diffs become too large to review sensibly, but it adds a merge step before anything downstream can read “all entries” as one list.

Is there a standard changelog file format, the way there’s a standard for RSS? Not a widely adopted one. Keep a Changelog proposes a Markdown convention, and several tools have their own; a changeset is a Markdown file with YAML front matter naming the package and the bump, which is the front-matter pattern described above. None of these is a format other tools read out of the box the way RSS readers universally understand RSS.


The technical claims in this article have not been independently reviewed. If something here is wrong, tell us and we will correct it.

Related on changeloop: Changelog tools compared, Changelog generator

changeloop
The team building a closed-loop changelog. Your users ask, your team ships, the person who asked gets told.