mrkeyoor.com_
Wed 05 Aug 19:57 UTC
npmUtilsupdated 05 Aug 2026

js-yaml

js-yaml is the YAML parser and writer most of the JavaScript ecosystem sits on. You call load() to turn a YAML string into plain objects and dump() to go the other way, which covers config files, CI definitions, and frontmatter. Version 5, released in June 2026, is a full rewrite: it targets YAML 1.2 by default, passes the entire official YAML test suite, and replaced the old schema and custom-tag APIs with a new design. It ships a single dependency (argparse, for its small CLI) plus browser builds and bundled TypeScript types.

Verdict

Still the default YAML choice for JavaScript, and v5 makes it spec-complete while staying actively maintained across three release lines. Budget real time for the v4 to v5 migration if you use custom tags, and reach for the yaml package when you must round-trip comments.

API stability3/5v5 (June 2026) was a breaking rewrite of schemas, custom tags, and dump options after five stable years on v4; load and dump survived, but anything deeper needs porting. The 4.x and 3.x lines still get patch releases.
Docs4/5The README documents every load and dump option with defaults and warnings, and the v4-to-v5 migration guide is detailed; advanced custom-tag work is documented mostly through the examples directory rather than a reference manual.
Maintenance5/5Pushed August 2026 with parallel releases on the 5.x, 4.3.x, and 3.15.x lines and only 7 open issues and PRs; the nodeca team has run the project since 2011.
Ecosystem5/5About 290M weekly downloads make it one of npm's most depended-on packages; ESLint-style tooling, docs generators, and frontmatter libraries all sit on top of it.

Use it if

  • You need to read or write YAML config in Node and want the library that linters, build tools, and frontmatter packages already depend on, so it is probably in your node_modules anyway
  • You care about spec correctness: v5 handles both YAML 1.2 and 1.1 and passes the official YAML test suite
  • You parse YAML from users or third parties and want built-in guards: maxAliases, maxDepth, and maxTotalMergeKeys cap alias bombs, deep nesting, and merge-key blowups
  • You want a small API surface: load, loadAll, dump, and a schema option cover almost every job
Skip it if

Setup reality

npm install js-yaml and you can parse immediately; no config, one dependency. The v5 surprises: there is no ESM default export, so import yaml from 'js-yaml' breaks and you need named or namespace imports; load('') now throws instead of returning undefined; and types are bundled, so drop @types/js-yaml if you had it. Teams coming from v4 with custom Type classes or dump styles have a genuine porting job because the tag model changed, not just the names. The migration guide is thorough and worth reading before you touch anything.

Patterns

Parse a YAML file into an objectload-yaml-file

import { load } from 'js-yaml'
import { readFileSync } from 'node:fs'

const config = load(readFileSync('config.yml', 'utf8'))

load() throws YAMLException on bad input, and since v5 an empty file throws too instead of returning undefined.

Parse a multi-document streamload-multi-document

import { loadAll } from 'js-yaml'

const docs = loadAll(source) // one array entry per --- document

load() throws on sources with --- separators; loadAll is the only way to read them, and it returns [] for empty input.

Serialize an object to YAMLdump-object-to-yaml

import { dump } from 'js-yaml'

const text = dump(
  { name: 'app', ports: [80, 443] },
  { indent: 2, sortKeys: true }
)

Default lineWidth is 80, so long strings get folded across lines; pass lineWidth: -1 to keep them intact.

Re-enable YAML merge keys (<<)enable-merge-keys

import { load, CORE_SCHEMA, mergeTag } from 'js-yaml'

const doc = load(source, {
  schema: CORE_SCHEMA.withTags(mergeTag)
})

The v5 default CORE_SCHEMA drops merge keys; without mergeTag a << line lands in your object as a literal '<<' property instead of merging the anchor.

Parse legacy YAML 1.1 documentsyaml-1-1-compat

import { load, YAML11_SCHEMA } from 'js-yaml'

const doc = load(source, { schema: YAML11_SCHEMA })
// !!timestamp -> Date, !!binary -> Uint8Array, !!set -> Set

Under the default 1.2 schema, timestamps stay strings and yes/no stay strings. YAML11_SCHEMA restores v4-style typing, but !!binary now yields Uint8Array, not Buffer.

Parse untrusted YAML with limitslimit-untrusted-input

import { load } from 'js-yaml'

const doc = load(userInput, {
  maxAliases: 0, // reject *ref aliases entirely
  maxDepth: 20   // default is 100
})

Alias expansion is how billion-laughs YAML bombs work; maxAliases: 0 rejects aliases outright and maxDepth caps collection nesting.

Control duplicate key behaviorduplicate-keys-json-mode

import { load } from 'js-yaml'

load('a: 1\na: 2')                 // throws: duplicate key
load('a: 1\na: 2', { json: true }) // { a: 2 }

Duplicate mapping keys throw by default; json: true switches to JSON.parse behavior where the last value wins.

Define a custom !tagcustom-scalar-tag

import { load, dump, CORE_SCHEMA, defineScalarTag } from 'js-yaml'

const regexpTag = defineScalarTag('!regexp', {
  resolve: (source) => new RegExp(source),
  identify: (data) => data instanceof RegExp,
  represent: (data) => data.source
})

const schema = CORE_SCHEMA.withTags(regexpTag)
load('pattern: !regexp ^a+$', { schema })

The v4 Type class is gone; tags are built with defineScalarTag, defineSequenceTag, or defineMappingTag and registered via schema.withTags(). instanceOf became identify.

Use from CommonJScommonjs-usage

const { load, dump } = require('js-yaml')

const doc = load('a: 1')

v5 has no default export by design: destructured require works, and ESM code should use named imports or import * as yaml, never import yaml from 'js-yaml'.

Get readable errors with file contexterror-with-filename

import { load, YAMLException } from 'js-yaml'

try {
  load(source, { filename: 'deploy.yml' })
} catch (e) {
  if (e instanceof YAMLException) console.error(e.message)
  else throw e
}

The filename option puts the path into error messages next to line and column, which matters when you parse many files in one run.

Alternatives

PackageRegistryPick it when
yamlnpmYou need comment and formatting preservation or programmatic document editing; it exposes the full document model instead of plain objects.
gray-matternpmYou only need to pull YAML frontmatter out of Markdown files; it wraps the parsing for you.