Hash#transform_keys

hash.transform_keys { |key| block } -> hash
Returns: Hash · Added in v2.5 · Updated March 16, 2026 · Hash Methods
ruby hash transformation keys

Hash#transform_keys creates a new hash by transforming each key using a block. Unlike Hash#each_with_object or manual iteration, this method provides a focused way to remap keys while keeping values intact.

Syntax

hash.transform_keys { |key| block }

The block receives each key and should return the new key to use.

Basic Usage

Simple key transformation

user = { name: "Alice", age: 30, city: "London" }

user.transform_keys { |key| key.to_s.upcase }
# => { "NAME" => "Alice", "AGE" => 30, "CITY" => "London" }

Symbol to string keys

config = { debug: true, timeout: 30, max_retries: 5 }

config.transform_keys(&:to_s)
# => { "debug" => true, "timeout" => 30, "max_retries" => 5 }

String to symbol keys

data = { "name" => "Bob", "age" => 25 }

data.transform_keys(&:to_sym)
# => { name: "Bob", age: 25 }

Transforming with Custom Logic

Prefix or suffix keys

env = { DB_HOST: "localhost", DB_PORT: 5432 }

env.transform_keys { |k| "APP_#{k}" }
# => { "APP_DB_HOST" => "localhost", "APP_DB_PORT" => 5432 }

Convert snake_case to camelCase

params = { user_name: "alice", user_email: "alice@example.com" }

params.transform_keys { |k| k.to_s.gsub(/_([a-z])/) { $1.upcase } }
# => { userName: "alice", userEmail: "alice@example.com" }

Flatten nested keys

nested = { "user.name" => "Alice", "user.age" => 30 }

nested.transform_keys { |k| k.split(".") }
# => { ["user", "name"] => "Alice", ["user", "age"] => 30 }

transform_keys vs map

Using transform_keys is more idiomatic than using map to transform keys:

hash = { a: 1, b: 2 }

# Less idiomatic
hash.map { |k, v| [k.to_s, v] }.to_h
# => { "a" => 1, "b" => 2 }

# More idiomatic
hash.transform_keys(&:to_s)
# => { "a" => 1, "b" => 2 }

transform_keys vs transform_keys!

The bang version transform_keys! modifies the hash in place:

config = { debug: true, verbose: false }

config.transform_keys!(&:to_s)
# config is now { "debug" => true, "verbose" => false }

Use transform_keys when you want an immutable operation (returning a new hash).

transform_keys vs transform_values

Transform keys operates on keys while keeping values the same:

scores = { alice: 95, bob: 82, carol: 78 }

scores.transform_keys(&:to_s)
# => { "alice" => 95, "bob" => 82, "carol" => 78 }

For transforming values instead, use transform_values:

scores.transform_values { |v| v + 10 }
# => { alice: 105, bob: 92, carol: 88 }

Chaining with Other Methods

Combine with select

data = { name: "Alice", age: 30, email: "alice@example.com", city: "London" }

data
  .transform_keys(&:to_s)
  .select { |k, _| k.start_with?("name", "email") }
# => { "name" => "Alice", "email" => "alice@example.com" }

Combine with transform_values

prices = { apple: 100, banana: 200, orange: 150 }

prices
  .transform_keys(&:to_s)
  .transform_values { |v| v * 1.1.round(2) }
# => { "apple" => 110.0, "banana" => 220.0, "orange" => 165.0 }

Combine with merge

defaults = { debug: false, timeout: 30 }

defaults.transform_keys(&:to_s).merge({ "debug" => true })
# => { "debug" => true, "timeout" => 30 }

In-Place Modification with transform_keys!

If you need to modify the original hash rather than creating a new one, use transform_keys!:

settings = { env: "production", log_level: "info" }

settings.transform_keys!(&:to_s)
# settings is now { "env" => "production", "log_level" => "info" }

This is useful when working with configuration objects that you want to modify directly.

Edge Cases

Empty hash

{}.transform_keys { |k| k.to_s }
# => {}

Duplicate transformed keys

When multiple keys transform to the same value, the last one wins:

hash = { a: 1, b: 2 }

hash.transform_keys { |k| :same_key }
# => { same_key: 2 }

This behavior matches how Ruby handles duplicate hash keys.

Block not provided

Without a block, transform_keys returns an enumerator:

hash = { a: 1, b: 2 }

hash.transform_keys.map { |k| k.to_s }
# => ["a", "b"]

Ruby Version Notes

  • Ruby 2.5: Introduced transform_keys
  • Ruby 2.5: Introduced transform_keys!
  • Ruby 2.5: Added blockless form returning enumerator

See Also