Hash#dig
hash.dig(*keys) -> value or nil Returns:
object or nil · Added in v2.3 · Updated March 13, 2026 · Hash Methods ruby hash methods nested
The .dig method safely retrieves nested values from hashes and arrays. It walks through the structure using each argument as a key, returning nil if at any point a key is missing instead of raising an error.
Signature
hash.dig(key, *keys) → value or nil
Parameters
| Parameter | Type | Description |
|---|---|---|
key | Object | The first key to look up |
*keys | Object | Additional keys for nested access |
Return Value
Returns the value at the nested key path, or nil if any key in the path is missing.
Basic Usage
user = {
name: "Alice",
address: {
city: "London",
zip: "SW1A 1AA"
}
}
user.dig(:address, :city) # => "London"
user.dig(:address, :country) # => nil
user.dig(:phone) # => nil
The method stops at the first missing key and returns nil, never raising an error.
Working with Arrays
.dig works with arrays too, using integer indices:
data = {
users: [
{ name: "Alice", scores: [95, 87] },
{ name: "Bob", scores: [78, 92] }
]
}
data.dig(:users, 0, :name) # => "Alice"
data.dig(:users, 1, :scores, 0) # => 78
data.dig(:users, 5, :name) # => nil
data.dig(:users, 0, :age) # => nil
Negative indices work as expected:
data.dig(:users, -1, :name) # => "Bob"
The Problem .dig Solves
Before .dig (introduced in Ruby 2.3), you had to manually check each level:
# Old way - tedious and error-prone
if user[:address] && user[:address][:city]
city = user[:address][:city]
end
# With dig - clean and safe
city = user.dig(:address, :city)
You could also use the && operator, but it gets unwieldy with deep nesting:
# Works but hard to read with multiple levels
city = user[:address] && user[:address][:city] && user[:address][:city][:name]
Common Use Cases
Configuration Reading
config = {
database: {
production: {
host: "db.example.com",
port: 5432
}
}
}
config.dig(:database, :production, :host)
# => "db.example.com"
config.dig(:database, :staging, :host)
# => nil
API Response Parsing
response = {
data: {
user: {
profile: {
avatar_url: "https://example.com/avatar.png"
}
}
}
}
response.dig(:data, :user, :profile, :avatar_url)
# => "https://example.com/avatar.png"
Default Values with nil Coalescing
city = user.dig(:address, :city) || "Unknown"
Comparison with Bracket Notation
| Aspect | Bracket Notation | .dig |
|---|---|---|
| Missing key | Raises KeyError | Returns nil |
| Deep nesting | Manual checks needed | Single call |
| Readability | Degrades with depth | Stays clean |
# Bracket notation - raises error
user[:address][:city] # => KeyError if :address missing
# dig - safe
user.dig(:address, :city) # => nil
See Also
hash-fetch— Fetch a value with a default or blockhash-each— Iterate over key-value pairs