Parse YAML Files
How to parse YAML configuration files in Python, Java, and JavaScript.
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
- For alternatives, see Parse TOML Files.
Use this resource when:
- Loading application configuration from
config.yamlordocker-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
| Technology | Library | Approach | Notes |
|---|---|---|---|
| Python | PyYAML | safe_load() | Full YAML 1.1, supports anchors/aliases |
| Python | ruamel.yaml | YAML() | Preserves comments and formatting on round-trip |
| JavaScript | js-yaml | load() / dump() | Fast, widely used, safe by default |
| Java | SnakeYAML | Yaml.load() | Standard for JVM, supports custom types |
| Java | Jackson YAML | ObjectMapper | Smooth POJO binding with Jackson |
| Go | gopkg.in/yaml.v3 | yaml.Unmarshal() | Native Go structs support |
What Works
- Always use
safe_loadin 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.loadwithoutLoaderin Python: This is deprecated and insecure; always usesafe_load - Indentation with tabs: YAML only accepts spaces; tabs cause parsing errors
- Confusing
:in unquoted strings:key: value:morebreaks 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_loador 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.
Related Resources
Parse JSON
How to parse JSON strings into native data structures across multiple programming languages.
RecipeValidate JSON Schema
How to validate JSON data against schemas in Python, Java, and JavaScript.
RecipeSerialize and Deserialize Data
How to serialize and deserialize data in JSON, XML, and YAML across Python, Java, and JavaScript.
RecipeParse TOML Files
How to parse TOML configuration files in Python, Java, and JavaScript.
RecipeParse XML Files
How to parse XML documents in Python, Java, and JavaScript with practical code examples.
RecipeParse Command Line Arguments
How to parse command line arguments in Python, Java, and Node.js CLI applications.
RecipeParse Markdown Files
How to parse Markdown to HTML and extract structured data in Python, Java, and JavaScript.