{"id":34682835,"url":"https://github.com/bug-ops/fast-yaml","last_synced_at":"2026-04-02T20:45:31.176Z","repository":{"id":328548821,"uuid":"1115449287","full_name":"bug-ops/fast-yaml","owner":"bug-ops","description":"Parse YAML at Rust speed. Full 1.2.2 spec, built-in linter, parallel processing. Native bindings for Python \u0026 Node.js.","archived":false,"fork":false,"pushed_at":"2026-03-25T17:06:08.000Z","size":1306,"stargazers_count":6,"open_issues_count":7,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-26T05:12:03.554Z","etag":null,"topics":["high-performance","linter","napi-rs","nodejs","parallel-processing","parser","pyo3","python","rust","yaml","yaml-linter","yaml-parser"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bug-ops.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-12T22:12:24.000Z","updated_at":"2026-03-25T17:05:38.000Z","dependencies_parsed_at":"2026-01-18T04:01:36.427Z","dependency_job_id":null,"html_url":"https://github.com/bug-ops/fast-yaml","commit_stats":null,"previous_names":["bug-ops/fast-yaml"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/bug-ops/fast-yaml","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bug-ops%2Ffast-yaml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bug-ops%2Ffast-yaml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bug-ops%2Ffast-yaml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bug-ops%2Ffast-yaml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bug-ops","download_url":"https://codeload.github.com/bug-ops/fast-yaml/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bug-ops%2Ffast-yaml/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31157106,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-29T17:31:56.304Z","status":"ssl_error","status_checked_at":"2026-03-29T17:31:41.973Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["high-performance","linter","napi-rs","nodejs","parallel-processing","parser","pyo3","python","rust","yaml","yaml-linter","yaml-parser"],"created_at":"2025-12-24T21:17:01.541Z","updated_at":"2026-04-02T20:45:31.170Z","avatar_url":"https://github.com/bug-ops.png","language":"Rust","readme":"# fast-yaml\n\n[![CI Status](https://img.shields.io/github/actions/workflow/status/bug-ops/fast-yaml/ci.yml?branch=main)](https://github.com/bug-ops/fast-yaml/actions)\n[![codecov](https://codecov.io/gh/bug-ops/fast-yaml/graph/badge.svg?token=E33WB16NUD)](https://codecov.io/gh/bug-ops/fast-yaml)\n[![Crates.io](https://img.shields.io/crates/v/fast-yaml-cli)](https://crates.io/crates/fast-yaml-cli)\n[![docs.rs](https://img.shields.io/docsrs/fast-yaml-core)](https://docs.rs/fast-yaml-core)\n[![PyPI](https://img.shields.io/pypi/v/fastyaml-rs)](https://pypi.org/project/fastyaml-rs/)\n[![npm](https://img.shields.io/npm/v/fastyaml-rs)](https://www.npmjs.com/package/fastyaml-rs)\n[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue)](LICENSE-MIT)\n\n**High-performance YAML 1.2.2 parser for Python and Node.js, powered by Rust.**\n\nDrop-in replacement for PyYAML and js-yaml. Matches or beats PyYAML C on small/medium files, **2-4x faster** than pure Python, **1.2-1.4x faster** than js-yaml. Full YAML 1.2.2 Core Schema compliance, comprehensive linting, and multi-threaded parallel processing.\n\n\u003e [!IMPORTANT]\n\u003e **YAML 1.2.2 Compliance** — Unlike PyYAML (YAML 1.1), `fast-yaml` follows the modern YAML 1.2.2 specification. This means `yes/no/on/off` are strings, not booleans.\n\n## Installation\n\n```bash\n# Python\npip install fastyaml-rs\n\n# Node.js\nnpm install fastyaml-rs\n\n# CLI\ncargo install fast-yaml-cli\n```\n\n\u003e [!WARNING]\n\u003e Requires Rust 1.88+, Python 3.10+ or Node.js 20+\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eBuild from source\u003c/b\u003e\u003c/summary\u003e\n\n```bash\ngit clone https://github.com/bug-ops/fast-yaml.git\ncd fast-yaml\n\n# Python\nuv sync \u0026\u0026 uv run maturin develop\n\n# Node.js\ncd nodejs \u0026\u0026 npm install \u0026\u0026 npm run build\n```\n\n\u003c/details\u003e\n\n## Architecture\n\nfast-yaml is organized as a modular Rust workspace with clear separation of concerns:\n\n```\nfast-yaml/\n├── crates/fast-yaml-core/     # Parser + Emitter + Streaming Formatter\n├── crates/fast-yaml-linter/   # Linter + Diagnostic Formatters\n├── crates/fast-yaml-parallel/ # Multi-threaded processing\n├── python/                    # PyO3 bindings\n└── nodejs/                    # NAPI-RS bindings\n```\n\n### Core Components\n\n| Component | Location | Input | Output | Use Case |\n|-----------|----------|-------|--------|----------|\n| **Parser** | `fast-yaml-core` | YAML text | `Value` (DOM) | Deserialize YAML to data structures |\n| **Emitter** | `fast-yaml-core` | `Value` (DOM) | YAML text | Serialize data structures to YAML |\n| **Streaming Formatter** | `fast-yaml-core` | Parser events | YAML text | Format YAML without building DOM |\n| **Linter** | `fast-yaml-linter` | YAML text | `Vec\u003cDiagnostic\u003e` | Validate YAML against rules |\n| **Parallel Processor** | `fast-yaml-parallel` | YAML files/streams | `BatchResult` | Parallel processing at document and file level |\n\n\u003e [!TIP]\n\u003e **Parser vs Streaming Formatter**: Parser builds a full DOM (use for data manipulation), Streaming Formatter processes events directly (use for formatting/conversion).\n\n\u003e [!TIP]\n\u003e **Linter vs Diagnostic Formatter**: Linter validates YAML and produces diagnostics, Diagnostic Formatter renders them for display (rustc-style text, JSON, SARIF).\n\n### Parallelism Types\n\n| Type | API | Use Case |\n|------|-----|----------|\n| **Document-level** | `parse_parallel()` | Parse multi-document YAML streams |\n| **File-level** | `process_files()`, `FileProcessor` | Process multiple files in parallel |\n| **CLI batch mode** | `fy format -j 8 dir/` | Format directories with parallel workers |\n\n\u003e [!NOTE]\n\u003e All parallelism is now unified in the `fast-yaml-parallel` crate. CLI batch mode and FFI bindings use this single implementation.\n\n## Quick Start\n\n### Python\n\n```python\nimport fast_yaml\n\ndata = fast_yaml.safe_load(\"\"\"\nname: fast-yaml\nfeatures: [fast, safe, yaml-1.2.2]\n\"\"\")\n\nyaml_str = fast_yaml.safe_dump(data)\n```\n\n\u003e [!TIP]\n\u003e Migrating from PyYAML? Just change your import: `import fast_yaml as yaml`\n\n### Node.js\n\n```typescript\nimport { safeLoad, safeDump } from 'fastyaml-rs';\n\nconst data = safeLoad(`name: fast-yaml`);\nconst yamlStr = safeDump(data);\n```\n\n### CLI\n\n```bash\n# Single file operations\nfy parse config.yaml           # Validate syntax\nfy format -i config.yaml       # Format in-place (exits with error if comments detected)\nfy format -i --strip-comments config.yaml  # Format and strip comments silently\nfy convert json config.yaml    # YAML → JSON\nfy lint config.yaml            # Lint with diagnostics\n\n# Batch mode (directories, globs, multiple files)\nfy format -i src/              # Format entire directory\nfy format -i \"**/*.yaml\"       # Format with glob pattern\nfy format -i -j 8 project/     # Parallel processing (8 workers)\nfy lint --exclude \"tests/**\" . # Lint all except tests\n```\n\n\u003e [!TIP]\n\u003e Batch mode activates automatically for directories, globs, or multiple files. Supports parallel processing, include/exclude patterns, and respects `.gitignore`.\n\n\u003e [!WARNING]\n\u003e `fy format` does **not** preserve YAML comments. If the input contains comments, the command exits with an error (exit code 1). Pass `--strip-comments` to acknowledge this and allow formatting to proceed — comments will be removed from the output.\n\n## Features\n\n- **High Performance** — Matches PyYAML C on small/medium files, 2-4x faster than pure Python\n- **YAML 1.2.2** — Full Core Schema compliance\n- **Drop-in API** — Compatible with PyYAML/js-yaml\n- **Batch Processing** — Multi-file operations with parallel workers, glob patterns, .gitignore support\n- **Linting** — Rich diagnostics with line/column tracking\n- **Parallel** — Multi-threaded processing for large files\n- **Safe** — Memory-safe Rust with minimal `unsafe` (FFI boundaries only, explicitly documented)\n\n\u003e [!TIP]\n\u003e Parallel processing provides 3-6x speedup on 4-8 core systems for multi-document files.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eFeature details\u003c/b\u003e\u003c/summary\u003e\n\n### Linting\n\n```python\nfrom fast_yaml._core.lint import lint\n\ndiagnostics = lint(\"key: value\\nkey: duplicate\")\nfor diag in diagnostics:\n    print(f\"{diag.severity}: {diag.message} at line {diag.span.start.line}\")\n```\n\n### Parallel Processing (Document-Level)\n\n```python\nfrom fast_yaml._core.parallel import parse_parallel, ParallelConfig\n\n# Parse ONE file with MULTIPLE documents in parallel\nmulti_doc_yaml = \"---\\nfoo: 1\\n---\\nbar: 2\\n---\\nbaz: 3\"\nconfig = ParallelConfig(thread_count=4, max_input_size=100*1024*1024)\ndocs = parse_parallel(multi_doc_yaml, config)  # 3 documents parsed in parallel\n```\n\n\u003e [!NOTE]\n\u003e This is document-level parallelism (parsing documents inside one file). For file-level parallelism (processing multiple files), use CLI batch mode: `fy format -i -j 8 directory/`\n\n\u003c/details\u003e\n\n## Performance\n\n\u003e [!NOTE]\n\u003e Three separate benchmark suites: **Python API** (vs PyYAML), **Node.js API** (vs js-yaml), and **CLI Batch Mode** (vs yamlfmt).\n\n\u003e [!NOTE]\n\u003e Process startup overhead (~15ms for Python, ~20-25ms for Node.js) affects small file benchmarks. In long-running servers (persistent processes), speedups would be 2-4x higher.\n\n\u003e [!TIP]\n\u003e Batch mode is where fast-yaml excels with parallel processing. Use `-j` to specify worker count.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eBenchmark results\u003c/b\u003e\u003c/summary\u003e\n\n### Python API vs PyYAML\n\n**Parse (loading):**\n\n| File Size | fast-yaml | PyYAML (C) | PyYAML (pure) | vs C | vs pure |\n|-----------|-----------|------------|---------------|------|---------|\n| Small (502B) | **15.5 ms** | 20.2 ms | 20.8 ms | **1.30x** | **1.34x** |\n| Medium (44KB) | **26.3 ms** | 26.4 ms | 61.2 ms | **1.00x** | **2.33x** |\n| Large (449KB) | 130.3 ms | **79.3 ms** | 429.6 ms | 0.61x | **3.30x** |\n\n**Dump (serialization):**\n\n| File Size | fast-yaml | PyYAML (C) | PyYAML (pure) | vs C | vs pure |\n|-----------|-----------|------------|---------------|------|---------|\n| Small (502B) | **15.7 ms** | 20.8 ms | 21.2 ms | **1.33x** | **1.35x** |\n| Medium (44KB) | **31.6 ms** | 31.7 ms | 82.7 ms | **1.00x** | **2.62x** |\n| Large (449KB) | 177.6 ms | **131.1 ms** | 653.8 ms | 0.74x | **3.68x** |\n\n**Key findings:**\n- **Small/Medium files**: fast-yaml matches or beats PyYAML C (1.0-1.3x speedup)\n- **Pure Python**: fast-yaml consistently 1.3-3.7x faster across all sizes\n- **Large files**: PyYAML C optimized for single large files; use fast-yaml's parallel mode for multi-document streams\n\nFull benchmarks: [benches/comparison](benches/comparison/)\n\n### Node.js API vs js-yaml (Apple M3 Pro, 12 cores)\n\n**Parse (loading):**\n\n| File Size | fast-yaml | js-yaml | Speedup |\n|-----------|-----------|---------|---------|\n| Small (502B) | **24.4 ms** | 28.1 ms | **1.15x** |\n| Medium (44KB) | **26.2 ms** | 31.9 ms | **1.22x** |\n| Large (449KB) | **40.4 ms** | 48.3 ms | **1.20x** |\n\n**Dump (serialization):**\n\n| File Size | fast-yaml | js-yaml | Speedup |\n|-----------|-----------|---------|---------|\n| Small (502B) | **24.1 ms** | 29.3 ms | **1.22x** |\n| Medium (44KB) | **27.1 ms** | 34.9 ms | **1.29x** |\n| Large (449KB) | **50.7 ms** | 72.1 ms | **1.42x** |\n\n**Key findings:**\n- **Consistent advantage**: fast-yaml 1.15-1.42x faster across all scenarios\n- **Best performance**: Large file dump operations (1.42x speedup)\n- **V8 JIT competitive**: js-yaml benefits from TurboFan optimization, reducing speedup vs pure Python\n- **Real-world servers**: In persistent processes without startup overhead, expect 2-4x speedup\n\n### CLI Single-File vs yamlfmt (Apple M3 Pro, 12 cores)\n\n| File Size | fast-yaml | yamlfmt | Result |\n|-----------|-----------|---------|--------|\n| Small (502 bytes) | **1.7 ms** | 3.1 ms | **1.80x faster** ✓ |\n| Medium (45 KB) | **2.5 ms** | 2.9 ms | **1.19x faster** ✓ |\n| Large (460 KB) | 8.4 ms | **2.9 ms** | yamlfmt 2.88x faster |\n\n### CLI Batch Mode vs yamlfmt\n\n| Workload | fast-yaml (parallel) | yamlfmt (sequential) | Speedup |\n|----------|---------------------|----------------------|---------|\n| 50 files (26 KB) | **4.3 ms** | 10.3 ms | **2.40x faster** ✓ |\n| 200 files (204 KB) | **8.0 ms** | 52.7 ms | **6.63x faster** ✓ |\n| 500 files (1 MB) | **15.5 ms** | 244.7 ms | **15.77x faster** ⚡ |\n| 1000 files (1 MB) | **23.4 ms** | 323.4 ms | **13.80x faster** ⚡ |\n\n**Key takeaway:** Batch mode with parallel workers provides 6-15x speedup on multi-file operations, making it ideal for formatting entire codebases.\n\n```bash\n# Run benchmarks\nbash benches/comparison/scripts/run_python_benchmark.sh  # Python API\nbash benches/comparison/scripts/run_nodejs_benchmark.sh  # Node.js API\nbash benches/comparison/scripts/run_batch_benchmark.sh   # CLI batch mode\n```\n\n**Test environment:** macOS 14, Apple M3 Pro (12 cores), fast-yaml 0.6.1, PyYAML 6.0.3, js-yaml 4.1.1, Node.js 25.2.1, yamlfmt 0.21.0\n\n\u003c/details\u003e\n\n## YAML 1.2.2 Differences\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDifferences from PyYAML (YAML 1.1)\u003c/b\u003e\u003c/summary\u003e\n\n| Feature | PyYAML (YAML 1.1) | fast-yaml (YAML 1.2.2) |\n|---------|-------------------|------------------------|\n| `yes/no` | `True/False` | `\"yes\"/\"no\"` (strings) |\n| `on/off` | `True/False` | `\"on\"/\"off\"` (strings) |\n| `014` (octal) | `12` | `14` (decimal) |\n| `0o14` (octal) | Error | `12` |\n\n```python\nfast_yaml.safe_load(\"yes\")    # \"yes\" (string, not True!)\nfast_yaml.safe_load(\"0o14\")   # 12 (octal)\nfast_yaml.safe_load(\"014\")    # 14 (decimal, NOT octal!)\n```\n\n\u003c/details\u003e\n\n## API Reference\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eLoading YAML\u003c/b\u003e\u003c/summary\u003e\n\n```python\n# Single document\ndata = fast_yaml.safe_load(yaml_string)\n\n# Multiple documents\nfor doc in fast_yaml.safe_load_all(yaml_string):\n    print(doc)\n\n# PyYAML-compatible\ndata = fast_yaml.load(yaml_string, Loader=fast_yaml.SafeLoader)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDumping YAML\u003c/b\u003e\u003c/summary\u003e\n\n```python\nyaml_str = fast_yaml.safe_dump(data)\n\n# With options\nyaml_str = fast_yaml.dump(\n    data,\n    indent=2,\n    width=80,\n    explicit_start=True,\n    sort_keys=False,\n)\n\n# Multiple documents\nyaml_str = fast_yaml.safe_dump_all([doc1, doc2, doc3])\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eType mappings\u003c/b\u003e\u003c/summary\u003e\n\n| YAML Type | Python Type |\n|-----------|-------------|\n| `null`, `~` | `None` |\n| `true`, `false` | `bool` |\n| `123`, `0x1F`, `0o17` | `int` |\n| `1.23`, `.inf`, `.nan` | `float` |\n| `\"string\"`, `'string'` | `str` |\n| `[a, b, c]` | `list` |\n| `{a: 1, b: 2}` | `dict` |\n\n\u003c/details\u003e\n\n## Security\n\nInput validation prevents denial-of-service attacks.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eSecurity limits\u003c/b\u003e\u003c/summary\u003e\n\n| Limit | Default | Configurable |\n|-------|---------|--------------|\n| Max input size | 100 MB | Yes (up to 1GB) |\n| Max documents | 100,000 | Yes (up to 10M) |\n| Max threads | 128 | Yes |\n\n\u003c/details\u003e\n\n## Project\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eProject structure\u003c/b\u003e\u003c/summary\u003e\n\n```\nfast-yaml/\n├── crates/\n│   ├── fast-yaml-core/     # Core YAML parser/emitter\n│   ├── fast-yaml-linter/   # Linting engine\n│   └── fast-yaml-parallel/ # Multi-threaded processing\n├── python/                 # PyO3 Python bindings\n├── nodejs/                 # NAPI-RS Node.js bindings\n└── Cargo.toml             # Workspace manifest\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eTechnology stack\u003c/b\u003e\u003c/summary\u003e\n\n| Component | Library |\n|-----------|---------|\n| YAML Parser | [saphyr](https://github.com/saphyr-rs/saphyr) |\n| Python Bindings | [PyO3](https://pyo3.rs/) |\n| Node.js Bindings | [NAPI-RS](https://napi.rs/) |\n| Parallelism | [Rayon](https://github.com/rayon-rs/rayon) |\n\n**Rust 2024 Edition** • **Python 3.10+** • **Node.js 20+**\n\n\u003c/details\u003e\n\n## Contributing\n\nContributions welcome! All PRs must pass CI checks:\n\n```bash\ncargo +nightly fmt --all\ncargo clippy --workspace --all-targets -- -D warnings\ncargo nextest run --workspace\n```\n\n## FAQ\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eWhy not just use PyYAML?\u003c/b\u003e\u003c/summary\u003e\n\nPyYAML is excellent. Use fast-yaml when you need performance (5-10x faster), YAML 1.2.2 compliance, built-in linting, or parallel processing.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eIs this a drop-in replacement?\u003c/b\u003e\u003c/summary\u003e\n\nFor `safe_*` functions, yes. Just change `import yaml` to `import fast_yaml as yaml`. Note that YAML 1.2.2 has different boolean/octal handling.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eWhen should I use parallel processing?\u003c/b\u003e\u003c/summary\u003e\n\n**Document-level parallelism** (`parse_parallel()` in Python/Node.js):\n- Use for single large files with multiple `---` separated documents\n- File size \u003e 1MB with dozens/hundreds of documents\n- Example: Log files, data dumps\n\n**File-level parallelism** (CLI batch mode):\n- Use for processing multiple separate files\n- Example: `fy format -i -j 8 src/` for entire directories\n\nFor single-document files, use `safe_load()`.\n\n\u003c/details\u003e\n\n## License\n\nLicensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE) at your option.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbug-ops%2Ffast-yaml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbug-ops%2Ffast-yaml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbug-ops%2Ffast-yaml/lists"}