Migrating from YAML
What to check, what has no equivalent, and how to verify a migration mechanically instead of by eye.
Lima is a deliberate subset of YAML block syntax — most existing YAML frontmatter parses under Lima unchanged. This guide is about the part that doesn’t: what to check, what has no equivalent, and how to verify a migration mechanically instead of by eye. For full syntax, see the Guide; for the underlying rules, the two normative specs (linked throughout) are authoritative.
The evidence this guide is based on
Two independent, reproducible sources back every claim below — neither is a synthetic benchmark, both are checked into the repository:
compat/— runs Lima’sparseCoreand js-yaml’sloadon the same input and reports where they agree and disagree. Run it yourself:bun install && bun run run(fromcompat/), orbun run run -- --jsonfor machine-readable output.-
fixtures/frontmatter-samples/— 16 hand-authored samples covering common real-world SSG/CMS conventions (Jekyll, Hugo, Astro, Next.js/MDX, Docusaurus, Eleventy, Gatsby, generic docs sites).
As of this repository’s current state, 14 of those 16 samples parse identically under Lima and js-yaml; 2 diverge, for the specific, understood reasons in Block scalars and trailing newlines and Quotes and escapes
below. That is a statement about these 16 samples, not a general compatibility percentage — 16 hand-picked
documents are breadth across common shapes, not statistical coverage of arbitrary YAML. Run
bun run run from compat/ against your own frontmatter for a real answer about your own documents.
Mostly unchanged
These constructs carry over from YAML to Lima with no rewriting needed:
- Plain scalars,
key: valuemappings, nested mappings. - Block sequences (
- item) and sequences of mapping objects. - Flow sequences (
[a, b, c]) and one level of flow mapping ({a: 1}). - Comments (
#), including#inside quoted strings staying literal. - Double-quoted strings and their standard escapes (
\n,\t,\\,\",\uXXXX, …). null/~/empty →null,true/false→ boolean, plain integers anddecimals → number.
- ISO 8601 dates (
2024-03-01,2024-03-01T09:00:00Z).
Needs checking
These parse under both, but can produce a different value, not an error — the risky category, because nothing will visibly fail:
- Timestamps without a
Tseparator or in a non-ISO shape. Limaadditionally recognises German (
DD.MM.YYYY) and slash (YYYY/MM/DD) forms, but a YAML timestamp with a space between date and time and an offset (2024-03-01 09:00 +02:00) matches none of Lima’s three forms and becomes a string, not a Date. See Types and dates. - Hex and octal numeric literals (
0xFF,0o77) — resolved as numbersby js-yaml’s own default schema (
0xFF→255,0o77→63, verified directly againstjs-yaml‘sCORE_SCHEMA, not just its more permissiveYAML11_SCHEMA). Lima always keeps these as strings. Binary literals (0b1010) are the one form that already agrees — js-yaml’s default schema doesn’t resolve those either, both keep it as the string"0b1010". - YAML’s wider implicit-boolean set (
yes/no/on/off/y/n) —not recognised by Lima at all; these stay strings. Whether this bites depends on the YAML parser and schema in use: js-yaml’s own default schema (
CORE_SCHEMA) already treatsyes/noas plain strings, same as Lima; only its more permissiveYAML11_SCHEMA(whatcompat/deliberately tests against, to match older/other real-world tooling — see Needs checking below) resolves them as booleans. Check which schema your current YAML tooling actually uses before assuming this affects you. Where it does apply, it’s the “Norway problem” fix, not a bug — but still a silent type change for anyone relying on the wider set. js-yaml’s own schema choice matters for comparison. Differentjs-yamlschemas resolve timestamps differently;compat/deliberately usesYAML11_SCHEMAto match what most real frontmatter tooling (Jekyll/Psych, older js-yaml, gray-matter) actually produces — see the comment at theload()call incompat/src/run.tsif a document behaves differently against a stricter schema.
Not supported
These throw or silently fall through — check Appendix A for the complete, reasoned list. The ones most likely to actually appear in real frontmatter:
>folded block scalar — use|with^^line-continuation instead.- Chomping indicators
|-/|+. - Nested flow structures (
[[1, 2]],{a: {b: 1}}as a value) andnested block sequences (array-in-array).
- YAML anchors/aliases (
&anchor,*alias) and tags (!!str,!!int). - Multi-document streams (
---/...separators within one file). - Merge keys (
<<). - Non-scalar mapping keys.
- American/British date formats (
MM/DD/YYYY,DD/MM/YYYY) — ambiguouswithout a locale, rejected outright rather than guessed at.
Types and dates
Full type table in the Guide. The date differences specifically:
All js-yaml results below use YAML11_SCHEMA, the schema compat/ deliberately compares against (see Needs checking) — js-yaml’s actual default schema ( CORE_SCHEMA
) doesn’t resolve timestamps at all, so every YAML row here would otherwise misleadingly read “String”.
| YAML input | js-yaml ( YAML11_SCHEMA) |
Lima |
|---|---|---|
2024-03-01T09:00:00Z |
Date | Date (unchanged) |
2024-03-01 09:00:00 (space, no offset) |
Date — YAML 1.1 accepts a space here | String — ISO forms require T |
2024-03-01 09:00 +02:00 (space, with offset) |
String — combining a space and an offset isn’t resolved either | String (same result, different reason) |
01.03.2024 (German form) |
String — not a YAML timestamp shape at all | Date — the type changes the other direction here |
2024/3/1 (single-digit month/day) |
String | String — Lima’s slash form requires two-digit month and day |
Quotes and escapes
The one confirmed divergence found by compat/‘s own sample set: YAML’s single-quote escape doubles the quote ( 'It''s fine' → It's fine). Lima’s single-quote escape is a backslash, matching its double-quote convention ( 'It\'s fine' → It's fine) — the doubling convention has no Lima equivalent and is not an error, so it fails silently:
subtitle: 'It''s more complicated than you think'
Under Lima this parses successfully as the literal string "It''s more complicated than you think" (quotes preserved, not collapsed) — reproduced directly in fixtures/frontmatter-samples/14-special-characters-quoted.yaml. Rewrite as 'It\'s more complicated than you think' (backslash) or switch to a double-quoted string.
Double-quoted strings and their escapes are otherwise unchanged from typical YAML usage. \0 is a documented exception on the Lima side — see the Guide.
Block scalars and trailing newlines
The second confirmed divergence: YAML’s plain |
literal block scalar defaults to “clip” chomping — the final line break is kept, additional trailing blank
lines are removed. Lima’s
| always strips all trailing newlines (YAML’s “strip”/ |- behaviour), never keeps one:
summary: |
Line one.
Line two.
YAML: "Line one.\nLine two.\n" (trailing newline kept). Lima: "Line one.\nLine two." (no trailing newline) — reproduced directly in fixtures/frontmatter-samples/16-long-description-block-scalar.yaml
. If a trailing newline is semantically required downstream, append it after parsing rather than relying on
the block scalar to carry it.
References — optional, not a YAML equivalent
($key) document references and (%key)
external partials are a Lima addition with no YAML equivalent — migrating YAML frontmatter never requires
using them. They’re layered on top of Core via a separate
parse/ parseReferences function; plain parseCore never interprets ($...)/ (%...)
at all, so existing frontmatter that happens to contain literal parentheses is unaffected either way. See the
Guide for the full syntax and the one-hop resolution limit.
Migrating step by step
There is no bundled migration tool in this repository yet — the concept below is a proposal, not something implemented here (see CLI concept for why).
- Audit before touching anything. Run
bun run runfromcompat/against your own frontmatter (adapt
fixtures/frontmatter-samples/or point the script at your own directory) to find real divergences in your actual documents, not hypothetical ones. - Fix flagged documents first, using the sections above — most fixes
are narrow (a date format, a quote style) and mechanical.
- Switch the parser, keep the files. Since Lima accepts a large,
deliberate YAML subset, most existing
.yaml/.mdfrontmatter needs no rewriting at all — only the specific constructs flagged in step 1. - Re-run the audit after switching to confirm no unexpected
divergence remains.
- Rollback is just reverting the parser swap — Lima doesn’t rewrite
or mutate source files, so there’s nothing migration-specific to undo in the frontmatter itself. Keep the old parser dependency until step 4 is clean.
A proposed CLI, not implemented
A natural next step would be a small, dependency-free CLI wrapping the compat/ comparison logic for a real project’s content directory:
lima-migrate check <dir> # report-only, exit code reflects match rate
lima-migrate --write <dir> # (future) rewrite frontmatter to Lima-safe form
check is the safe, idempotent half — read-only, same shape as compat/’s existing report, just pointed at a real content tree instead of fixtures/. --write is deliberately not proposed for immediate implementation.
An automatic rewriter is a much larger commitment (it needs to preserve everything a human author cares about
— comments, formatting, key order — while only changing the specific constructs that actually diverge) and
deserves its own design, test suite, and maintainer sign-off before it touches anyone’s real content. This
document proposes the
check half as a reasonable, low-risk addition; --write should stay a documented idea until someone deliberately decides to build it.