Ruby JSON
last modified October 18, 2026
JSON (JavaScript Object Notation) is a lightweight text format for exchanging data. Ruby's standard library json converts between JSON text and Ruby objects. This guide covers parsing, generating, pretty printing, nested data, file input and output, and error handling.
Parsing JSON
The json library is part of the Ruby standard library, so it only needs require 'json'. JSON.parse converts a JSON string into Ruby hashes and arrays. By default, object keys are strings; passing symbolize_names: true turns them into symbols.
#!/usr/bin/env ruby
require 'json'
json_str = '{"name": "Alice", "age": 30, "languages": ["Ruby", "Python"]}'
data = JSON.parse(json_str)
puts data["name"]
puts data["languages"].inspect
sym = JSON.parse(json_str, symbolize_names: true)
puts sym[:name]
puts sym.keys.inspect
puts sym[:languages].first
The first call returns a hash with string keys, so values are read with data["name"]. The second call with symbolize_names: true allows access with sym[:name]. JSON arrays become Ruby arrays.
$ ./parse.rb Alice ["Ruby", "Python"] Alice [:name, :age, :languages] Ruby
Generating JSON
JSON.generate serializes a Ruby object to a compact JSON string. The to_json method, added by the library, does the same thing directly on any object. Hashes, arrays, strings, numbers, booleans and nil are all supported.
#!/usr/bin/env ruby
require 'json'
hash = { name: "Bob", age: 25, active: true, scores: [90, 85.5], note: nil }
puts JSON.generate(hash)
puts hash.to_json
puts [1, "two", 3.0].to_json
puts "plain string".to_json
puts 42.to_json
Both JSON.generate(hash) and hash.to_json produce identical compact output. Symbol keys become strings, and nil becomes null. Scalar values such as strings and numbers can also be converted.
$ ./generate.rb
{"name":"Bob","age":25,"active":true,"scores":[90,85.5],"note":null}
{"name":"Bob","age":25,"active":true,"scores":[90,85.5],"note":null}
[1,"two",3.0]
"plain string"
42
Pretty printing
JSON.pretty_generate produces indented, human-readable JSON. It is useful for configuration files, logs, and debugging output.
#!/usr/bin/env ruby
require 'json'
book = {
title: "Ruby Basics",
year: 2024,
authors: ["Jan", "Eve"],
publisher: { name: "ZetCode", city: "Bratislava" }
}
puts JSON.pretty_generate(book)
Nested hashes and arrays are each indented on their own lines. The structure is the same as in compact form, only the whitespace differs.
$ ./pretty.rb
{
"title": "Ruby Basics",
"year": 2024,
"authors": [
"Jan",
"Eve"
],
"publisher": {
"name": "ZetCode",
"city": "Bratislava"
}
}
Nested objects and arrays
Real-world JSON often nests objects inside arrays and arrays inside objects. This example parses such a document from a heredoc and walks through it with each, sum, and dig.
#!/usr/bin/env ruby
require 'json'
json_str = <<~JSON
{
"company": "Acme",
"employees": [
{ "name": "Ann", "skills": ["Ruby", "SQL"] },
{ "name": "Ben", "skills": ["Go"] }
],
"office": { "city": "Paris", "floors": [1, 2, 3] }
}
JSON
data = JSON.parse(json_str, symbolize_names: true)
puts data[:company]
data[:employees].each do |emp|
puts "#{emp[:name]}: #{emp[:skills].join(', ')}"
end
puts data[:office][:floors].sum
puts data.dig(:employees, 0, :skills, 1)
Hash lookups with symbol keys reach into the nested structure. dig safely traverses a path of keys and array indexes, returning nil if any step is missing.
$ ./nested.rb Acme Ann: Ruby, SQL Ben: Go 6 SQL
Reading and writing files
JSON data is commonly stored in files. File.write saves a string to disk, File.read loads it back, and JSON.parse turns the text into a Ruby structure. The file is removed at the end to keep the example self-contained.
#!/usr/bin/env ruby
require 'json'
path = "data.json"
config = { host: "localhost", port: 8080, debug: false }
File.write(path, JSON.pretty_generate(config))
loaded = JSON.parse(File.read(path), symbolize_names: true)
puts "Host: #{loaded[:host]}"
puts "Port: #{loaded[:port]}"
puts File.read(path)
File.delete(path)
The configuration hash is written as pretty-printed JSON, read back with symbolized keys, and printed. The file contents match what was written.
$ ./file_io.rb
Host: localhost
Port: 8080
{
"host": "localhost",
"port": 8080,
"debug": false
}
Handling invalid JSON
When the input is not valid JSON, JSON.parse raises JSON::ParserError. Wrap parsing in begin/rescue to handle malformed input gracefully. The example tries a valid string, a misspelled literal, and an unterminated array.
#!/usr/bin/env ruby
require 'json'
inputs = ['{"ok": true}', '{"ok": tru}', '[1, 2,']
inputs.each do |text|
begin
puts JSON.parse(text).inspect
rescue JSON::ParserError => e
puts "Invalid JSON: #{text}"
puts "Error class: #{e.class}"
end
end
The valid input parses into a hash. The two malformed inputs raise JSON::ParserError, which is caught and reported instead of crashing the program.
$ ./invalid.rb
{"ok"=>true}
Invalid JSON: {"ok": tru}
Error class: JSON::ParserError
Invalid JSON: [1, 2,
Error class: JSON::ParserError
List all Ruby tutorials.
Author
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.