Fast YAML parsing for Ruby via rapidyaml — a C++ YAML library. Drop-in replacement for Psych.
> cd benchmarketing
> ruby psych_load_vs_rapidyaml_load.rb
ruby 3.4.9 (2026-03-11 revision 76cca827ab) +PRISM [x86_64-linux]
Warming up --------------------------------------
psych 5.000 i/100ms
rapidyaml 23.000 i/100ms
Calculating -------------------------------------
psych 58.235 (± 1.7%) i/s (17.17 ms/i) - 585.000 in 10.045480s
rapidyaml 237.917 (± 1.3%) i/s (4.20 ms/i) - 2.392k in 10.053920s
Comparison:
rapidyaml: 237.9 i/s
psych: 58.2 i/s - 4.09x slower
I have received results varying from about 3-4x faster - as always, YMMV.
gem "rapidyaml"Building from source requires a C++17 compiler. No extra system libraries needed — rapidyaml is vendored.
The API is compatible with Psych:
require "rapidyaml"
# Parse YAML
data = RapidYAML.load("key: value\nlist:\n - 1\n - 2\n")
# => {"key" => "value", "list" => [1, 2]}
# Symbolized keys
data = RapidYAML.load("key: value\n", symbolize_names: true)
# => {key: "value"}
# safe_load is equivalent (rapidyaml never executes arbitrary code)
data = RapidYAML.safe_load(yaml_string)
# Serialize
yaml = RapidYAML.dump({ name: "Alice", age: 30 })
# File I/O
data = RapidYAML.load_file("config.yaml")
RapidYAML.dump_file(data, "output.yaml")| Psych method | RapidYAML equivalent |
|---|---|
Psych.load |
RapidYAML.load |
Psych.safe_load |
RapidYAML.safe_load |
Psych.unsafe_load |
RapidYAML.unsafe_load |
Psych.dump |
RapidYAML.dump |
Psych.safe_dump |
RapidYAML.safe_dump |
Psych.dump_stream |
RapidYAML.dump_stream |
Psych.load_file |
RapidYAML.load_file |
Psych.unsafe_load_file |
RapidYAML.unsafe_load_file |
Psych.dump_file |
RapidYAML.dump_file |
Psych.load_stream |
RapidYAML.load_stream |
Psych.safe_load_stream |
RapidYAML.safe_load_stream |
Psych.libyaml_version |
RapidYAML.libyaml_version (returns rapidyaml version) |
Scalar coercion matches Psych defaults: true/false → Boolean, integers, floats, ~/null → nil.
unsafe_load and unsafe_load_file are provided for drop-in compatibility. Because rapidyaml never executes arbitrary Ruby object tags, they behave identically to load and load_file — there is no unsafe code path.
rapidyaml and Psych can be loaded simultaneously. They occupy different namespaces (RapidYAML vs Psych) and do not interfere with each other. You can use rapidyaml for hot paths where parse speed matters and fall back to Psych where you need AST access or custom tag handling:
require "rapidyaml"
require "psych"
# Fast path
config = RapidYAML.load(File.read("large_config.yaml"))
# AST manipulation still goes through Psych
tree = Psych.parse(some_yaml)Psych exposes a visitor-based AST through Psych.parse, Psych.parse_file, Psych.parse_stream, and Psych.parser. These return Psych::Nodes::Document trees and support streaming visitors via Psych::Handler.
rapidyaml has no equivalent. The library resolves the ryml parse tree directly to Ruby objects and does not expose an intermediate AST. If your code depends on Psych::Nodes, Psych::TreeBuilder, Psych::Visitors, or custom Psych::Handler subclasses, it is not compatible with this gem.
bundle install
bundle exec rake compile
bundle exec rake testMIT — see LICENSE.