Skip to content
StackPractices
beginner By StackPractices

Parse YAML Files

How to parse YAML configuration files in Python, Java, and JavaScript.

Topics: data

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

YAML is the de facto standard for configuration files in DevOps, CI/CD pipelines, and application settings. Its human-readable syntax supports nested structures, comments, anchors, and aliases. Parsing YAML programmatically enables automated configuration validation, environment-specific overrides, and on-demand service discovery.

When to Use

Use this resource when:

  • Loading application configuration from config.yaml or docker-compose.yml
  • Parsing Kubernetes manifests, Ansible playbooks, or GitHub Actions workflows
  • Converting YAML to JSON for APIs that only accept JSON payloads
  • Validating YAML structure against a schema before deployment

Solution

Python

# PyYAML is the standard library for YAML in Python
# pip install pyyaml
import yaml

with open('config.yaml', 'r') as f:
    config = yaml.safe_load(f)

print(config['database']['host'])
# Dump Python objects back to YAML
import yaml

data = {'app': {'name': 'myapp', 'debug': False}}
print(yaml.safe_dump(data, default_flow_style=False))

JavaScript

// js-yaml is the most popular YAML parser for Node.js
// npm install js-yaml
import yaml from 'js-yaml';
import fs from 'fs';

const doc = yaml.load(fs.readFileSync('config.yaml', 'utf8'));
console.log(doc.database.host);
// Dump objects to YAML
import yaml from 'js-yaml';

const data = { app: { name: 'myapp', debug: false } };
console.log(yaml.dump(data));

Java

// SnakeYAML is the standard YAML library for Java
// Maven: org.yaml:snakeyaml
import org.yaml.snakeyaml.Yaml;
import java.io.FileInputStream;
import java.util.Map;

public class YamlParser {
    public static void main(String[] args) throws Exception {
        Yaml yaml = new Yaml();
        try (FileInputStream fis = new FileInputStream("config.yaml")) {
            Map<String, Object> config = yaml.load(fis);
            Map<String, Object> db = (Map<String, Object>) config.get("database");
            System.out.println(db.get("host"));
        }
    }
}

Explanation

YAML parsers convert the human-friendly syntax into native data structures (dicts/maps, lists, scalars). The safe_load / safe_dump variants in Python and load in SnakeYAML restrict object construction to basic types, preventing arbitrary code execution from untrusted YAML.

YAML’s anchors (&) and aliases (*) allow DRY configuration by referencing repeated blocks. Multi-line strings use | for literal blocks and > for folded blocks. Tags (!!str, !!int) explicitly type scalars.

Variants

TechnologyLibraryApproachNotes
PythonPyYAMLsafe_load()Full YAML 1.1, supports anchors/aliases
Pythonruamel.yamlYAML()Preserves comments and formatting on round-trip
JavaScriptjs-yamlload() / dump()Fast, widely used, safe by default
JavaSnakeYAMLYaml.load()Standard for JVM, supports custom types
JavaJackson YAMLObjectMapperSmooth POJO binding with Jackson
Gogopkg.in/yaml.v3yaml.Unmarshal()Native Go structs support

What Works

  • Always use safe_load in Python to avoid executing arbitrary code from untrusted YAML
  • Validate YAML against JSON Schema after parsing to catch structural errors early
  • Keep secrets out of YAML files; use environment variable substitution instead
  • Use anchors and aliases for repeated configuration blocks to reduce duplication
  • Store YAML files in version control with pull request reviews for configuration changes

Common Mistakes

  • Using yaml.load without Loader in Python: This is deprecated and insecure; always use safe_load
  • Indentation with tabs: YAML only accepts spaces; tabs cause parsing errors
  • Confusing : in unquoted strings: key: value:more breaks parsing; quote the value
  • Not handling merge keys (<<:) correctly: Some parsers ignore or mishandle YAML merge syntax
  • Expecting order preservation in mappings: YAML mappings are technically unordered; use sequences for ordered data

Advanced: YAML Anchors and Aliases

# Define reusable blocks with anchors
defaults: &defaults
  timeout: 30
  retries: 3
  log_level: info

production:
  <<: *defaults
  log_level: warn
  retries: 5

staging:
  <<: *defaults
  log_level: debug

Anchors (&name) define a block of YAML that can be reused. Aliases (*name) reference that block. Merge keys (<<: *name) inline the anchored content into the current mapping. This reduces duplication in CI/CD pipelines, Docker Compose files, and Kubernetes manifests. Not all parsers support merge keys — check your library’s documentation.

Advanced: Multi-Document YAML

import yaml

# Parse multiple YAML documents from a single file
with open('k8s-manifests.yaml', 'r') as f:
    for doc in yaml.safe_load_all(f):
        if doc:
            print(f"Kind: {doc.get('kind')}, Name: {doc.get('metadata', {}).get('name')}")

Multi-document YAML uses --- as a document separator. Kubernetes manifests, Helm templates, and CI/CD pipelines use this format to define multiple resources in one file. Use safe_load_all() (Python) or yaml.loadAll() (JavaScript) to iterate over documents. Each document is independent — anchors defined in one document are not visible in others.

Advanced: YAML Schema Validation

import yaml from 'js-yaml';
import Ajv from 'ajv';
import fs from 'fs';

const ajv = new Ajv();
const schema = JSON.parse(fs.readFileSync('schema.json', 'utf8'));
const validate = ajv.compile(schema);

const doc = yaml.load(fs.readFileSync('config.yaml', 'utf8'));
if (!validate(doc)) {
  console.error('Validation errors:', validate.errors);
  process.exit(1);
}
console.log('YAML config is valid');

Parse YAML to a JavaScript object, then validate it against a JSON Schema using Ajv. This catches missing required fields, type mismatches, and constraint violations before the config is used. Define schemas for Kubernetes manifests, CI/CD configs, and application settings to catch errors at load time.

Advanced: Custom YAML Tags

import yaml
import os

class EnvVar(yaml.SafeLoader):
    pass

def env_var_constructor(loader, node):
    value = loader.construct_scalar(node)
    return os.environ.get(value, '')

EnvVar.add_constructor('!env', env_var_constructor)

with open('config.yaml', 'r') as f:
    config = yaml.load(f, Loader=EnvVar)

Custom tags let you extend YAML with application-specific semantics. The !env tag resolves environment variables at parse time, keeping secrets out of YAML files. Define constructors for !include (file embedding), !ref (cross-references), or !base64 (encoded values). Register constructors on a custom loader subclass to keep safe_load behavior for standard tags.

Advanced: Writing YAML Files

import yaml

config = {
    'app': {
        'name': 'myapp',
        'version': '2.1.0',
        'debug': False
    },
    'database': {
        'host': 'localhost',
        'port': 5432,
        'pool_size': 10
    },
    'features': ['auth', 'logging', 'metrics']
}

with open('config.yaml', 'w') as f:
    yaml.safe_dump(config, f, default_flow_style=False, sort_keys=False)

Use safe_dump to write YAML without custom tags. Set default_flow_style=False for block-style output (more readable). Set sort_keys=False to preserve insertion order (Python 3.7+). PyYAML does not preserve comments from the original file. For comment preservation, use ruamel.yaml which supports round-trip editing.

Advanced: YAML Flow vs Block Style

# Block style (default, more readable)
features:
  - auth
  - logging
  - metrics

# Flow style (compact, JSON-like)
features: [auth, logging, metrics]

# Mixed (block for top-level, flow for small lists)
database: {host: localhost, port: 5432}
servers:
  - {name: web-1, ip: 10.0.0.1}
  - {name: web-2, ip: 10.0.0.2}

Block style uses indentation to show structure. Flow style uses {} and [] like JSON. Use block style for human-edited files because it is easier to read and edit. Use flow style for small inline values or when generating YAML programmatically. Mixing both is valid — use block for the document structure and flow for compact inline values.

When to Avoid

  • Untrusted input: YAML’s tag system can execute arbitrary code; use safe_load or disable custom tags
  • Performance-critical parsing: YAML is slower to parse than JSON; for high-throughput APIs, use JSON instead
  • Simple configs: For flat key-value configs, TOML or INI are simpler and less error-prone
  • Machine-to-machine: JSON is more compact and universally supported for API payloads

Frequently Asked Questions

Should I use YAML or JSON for configuration?

Use YAML for human-edited configuration files because comments, anchors, and cleaner syntax improve maintainability. Use JSON for machine-generated data and API payloads because its stricter syntax eliminates ambiguity.

How do I parse large YAML files efficiently?

Use streaming parsers: Python ruamel.yaml with YAML().load() generator, or SnakeYAML with Yaml.load(stream) which processes the file incrementally. For extremely large files, consider converting to JSON Lines or using a database.

Can I validate YAML against a JSON Schema?

Yes. Parse the YAML to a native data structure, then validate that structure against a JSON Schema using jsonschema (Python), Ajv (JS), or networknt (Java). This catches missing fields and type mismatches before deployment.

How do I handle YAML security?

Always use safe_load in Python (never yaml.load without a safe loader). In JavaScript, js-yaml is safe by default. Avoid loading YAML from untrusted sources — custom tags can execute arbitrary code. If you must process untrusted YAML, disable custom tag constructors and restrict the parser to basic types.

What is the difference between YAML 1.1 and 1.2?

YAML 1.2 (2009) aligns the core schema with JSON: yes/no/on/off are strings, not booleans. YAML 1.1 treats these as booleans, which causes subtle bugs. Most libraries (PyYAML, js-yaml) implement YAML 1.1. Use ruamel.yaml for YAML 1.2 compliance. Always quote strings like yes or no to avoid ambiguity.

How do I preserve comments when writing YAML?

PyYAML’s safe_dump does not preserve comments. Use ruamel.yaml which supports round-trip editing: load with YAML().load(), modify the data, then YAML().dump() — comments and formatting are preserved. In JavaScript, yaml (eemeli/yaml) preserves comments through its CST (Concrete Syntax Tree) API.

Can I use YAML for API payloads?

YAML is not recommended for API payloads. JSON is the standard for HTTP APIs because it is universally supported, compact, and fast to parse. YAML’s flexibility (anchors, tags, implicit typing) introduces ambiguity that can cause security issues and parsing inconsistencies across implementations. Use YAML for configuration only.