Hash#merge
hash.merge(*others) -> hash hash · Added in v1.8 · Updated March 13, 2026 · Hash Methods The merge method combines a hash with one or more other hashes, returning a new hash. When keys overlap between hashes, the value from the later hash wins. This makes merge essential for combining configurations, updating defaults, and building up hashes from multiple sources.
Signature
hash.merge(*others) → new_hash
hash.merge(*others) { |key, old_value, new_value| block } → new_hash
Parameters
| Parameter | Type | Description |
|---|---|---|
*others | Hash | One or more hashes to merge into the receiver. Each must be a Hash object. |
Return Value
Returns a new Hash object containing all key-value pairs from the original hash and the merged hashes. The original hashes remain unchanged.
Basic Usage
defaults = { theme: 'dark', language: 'en' }
user_prefs = { theme: 'light' }
merged = defaults.merge(user_prefs)
merged # => {:theme=>"light", :language=>"en"}
The original hashes stay intact:
defaults # => {:theme=>"dark", :language=>"en"}
user_prefs # => {:theme=>"light"}
You can merge multiple hashes at once:
base = { a: 1 }
overrides = { b: 2 }
local = { c: 3 }
base.merge(overrides, local)
# => {:a=>1, :b=>2, :c=>3}
The last value wins when keys overlap:
h1 = { a: 1, b: 2 }
h2 = { b: 3, c: 4 }
h3 = { b: 5 }
h1.merge(h2, h3)
# => {:a=>1, :b=>5, :c=>4}
In-Place vs New Hash
Ruby provides two ways to merge: one that creates a new hash, and one that modifies in place.
merge (Creates New Hash)
The merge method returns a new hash and leaves the original unchanged:
config = { host: 'localhost', port: 3000 }
new_config = config.merge({ port: 8080 })
config # => {:host=>"localhost", :port=>3000}
new_config # => {:host=>"localhost", :port=>8080}
This is useful when you want to preserve the original data.
merge! (Modifies in Place)
The merge! method (also known as update) modifies the hash directly:
config = { host: 'localhost', port: 3000 }
config.merge!({ port: 8080 })
config # => {:host=>"localhost", :port=>8080}
Use this when you intentionally want to update the original hash. It’s faster since it doesn’t create a new object.
Block Form (Conflict Resolution)
When keys overlap, you can provide a block to resolve conflicts yourself. The block receives three arguments: the key, the value from the original hash, and the value from the merging hash.
prices = { apple: 1.00, banana: 0.50 }
sale_prices = { apple: 0.80, banana: 0.40, orange: 0.75 }
prices.merge(sale_prices) { |key, old, new| old * 0.9 }
# => {:apple=>0.9, :banana=>0.36, :orange=>0.75}
The block lets you compute custom values. Common patterns include:
# Keep the higher value
h1.merge(h2) { |_k, v1, v2| v1 > v2 ? v1 : v2 }
# Sum numeric values
h1.merge(h2) { |_k, v1, v2| v1 + v2 }
# Collect values into arrays
h1.merge(h2) { |_k, v1, v2| [v1, v2] }
When there’s no conflict, the block is never called:
h1 = { a: 1 }
h2 = { b: 2 }
h1.merge(h2) { |key, old, new| raise 'Never called' }
# => {:a=>1, :b=>2}
Common Use Cases
Configuration Defaults
DEFAULTS = { timeout: 30, retries: 3, debug: false }
user_config = { timeout: 60 }
config = DEFAULTS.merge(user_config)
# => {:timeout=>60, :retries=>3, :debug=>false}
Merging User Input
form_data = { name: '', email: '' }
required_fields = { name: nil, email: nil, phone: nil }
submitted = { name: 'Alice', email: 'alice@example.com' }
form_data.merge(required_fields).merge(submitted)
# => {:name=>"Alice", :email=>"alice@example.com", :phone=>nil}
Building Options Hashes
default_options = {
verbose: false,
format: 'json',
timeout: 30
}
user_options = { verbose: true }
default_options.merge(user_options)
# => {:verbose=>true, :format=>"json", :timeout=>30}
See Also
hash#fetch— Fetch a value with a default or blockhash#delete— Remove entries from a hashhash-replace— Replace all entries in a hash