

This would be handy when parsing YAML.

my_hash = YAML.load_file('yml')

I'd like to be able to use:


Rather than:

  • dup? – Ian Vaughan May 11 '12 at 14:38
  • 76

31 Answers 31


If you want a one-liner,



  • 5
  • 4
  • 36
  • 7
  • 8

Here's a better method, if you're using Rails:


The end.


myhash.keys.each do |key|
  • 6
    to_options is an alias for sybolize_keys. – ma11hew28 Feb 9 '11 at 2:13
  • 45
  • 3
  • 23
  • 13


require 'yaml'
require 'pp'
yaml_str = "
  - host: host1.example.com
    port: 10000
  - host: host2.example.com
    port: 20000
yaml_sym = "
  - :host: host1.example.com
    :port: 10000
  - :host: host2.example.com
    :port: 20000
pp yaml_str = YAML.load(yaml_str)
puts yaml_str.keys.first.class
pp yaml_sym = YAML.load(yaml_sym)
puts yaml_sym.keys.first.class


  • 15
    Sweet! Is there a way to set YAML#load_file to default all keys to symbols instead of strings w/o having to begin every key with a colon? – ma11hew28 Feb 9 '11 at 2:31

Even more terse:

  • 5
  • 11
    It doesn't symbolize nested hashes. – rgtk May 17 '14 at 16:34
  • 14
    A more readable version: my_hash.map { |k, v| [k.to_sym, v] }.to_h – Dennis Apr 15 '16 at 11:59



see also:



  require 'facets'


  • 2

Since Ruby 2.5.0 you can use Hash#transform_keys or Hash#transform_keys!.

{'a' => 1, 'b' => 2}.transform_keys(&:to_sym) #=> {:a => 1, :b => 2}
  • Also works with transform_values apidock.com/rails/Hash/transform_values. That's really nice because there doesn't seem to be an equivalent for modifying values like there is with stringify_keys or symbolize_keys. – Mike Vallano Dec 13 '18 at 20:47
  • is there a way to deep symbolize keys – Abhay Kumar Jun 27 at 6:03



Here's a way to deep symbolize an object

def symbolize(obj)
    return obj

I really like the Mash gem.



If you are using json, and want to use it as a hash, in core Ruby you can do it:

json_obj = JSON.parse(json_str, symbolize_names: true)

symbolize_names: If set to true, returns symbols for the names (keys) in a JSON object. Otherwise strings are returned. Strings are the default.

Doc: Json#parse symbolize_names



  • 25
  • Also, it doesn't work with nested hash – Ahmad hamza May 24 '17 at 7:52

A modification to @igorsales answer

class Object
  def deep_symbolize_keys
    return self
  • It would be helpful if you included why you were modifying the object for people scanning through answers. – Dbz Feb 22 at 0:18
{'g'=> 'a', 2 => {'v' => 'b', 'x' => { 'z' => 'c'}}}.deep_symbolize_keys!

Converts to:

{:g=>"a", 2=>{:v=>"b", :x=>{:z=>"c"}}}
  • 3
    deep_symbolize_keys is added in Rails' Hash extension, but it's not part of Ruby core. – BoosterStage Jan 26 '18 at 2:07

So many answers here, but the one method rails function is hash.symbolize_keys


This is my one liner for nested hashes

def symbolize_keys(hash)
  hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v }
  • FYI, only works for Rails. In which case, HashWithIndifferentAccess may be a better alternative. – Adam Grant Jul 16 '17 at 22:50

In case the reason you need to do this is because your data originally came from JSON, you could skip any of this parsing by just passing in the :symbolize_names option upon ingesting JSON.

No Rails required and works with Ruby >1.9

JSON.parse(my_json, :symbolize_names => true)

You could be lazy, and wrap it in a lambda:

my_hash = YAML.load_file('yml')
my_lamb = lambda { |key| my_hash[key.to_s] }



To do that, you could use Hash#merge



#=> 1
irb> y
#=> 1
irb> y['a'] = 3
#=> 3
irb> y


irb> r[:c] # init block is called
#=> 4
irb> r
#=> 4
irb> r[:c] = 7
#=> 7
irb> r



Would something like the following work?

new_hash = Hash.new



a shorter one-liner fwiw:


How about this:

my_hash = HashWithIndifferentAccess.new(YAML.load_file('yml'))

# my_hash['key'] => "val"
# my_hash[:key]  => "val"

This is for people who uses mruby and do not have any symbolize_keys method defined:

class Hash
  def symbolize_keys!
    self.keys.each do |k|
      if self[k].is_a? Hash
      if k.is_a? String
        raise RuntimeError, "Symbolizing key '#{k}' means overwrite some data (key :#{k} exists)" if self[k.to_sym]
        self[k.to_sym] = self[k]
    return self

The method:

  • symbolizes only keys that are String
  • if symbolize a string means to lose some informations (overwrite part of hash) raise a RuntimeError
  • symbolize also recursively contained hashes
  • return the symbolized hash
  • works in place!
  • 1
    There's a typo in your method, you forgot the ! in symbolize_keys. Otherwise works fine. – Ka Mok Sep 7 '17 at 23:44

The array we want to change.

strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]

Make a new variable as an empty array so we can ".push" the symbols in.

symbols = [ ]

Here's where we define a method with a block.

strings.each {|x| symbols.push(x.intern)}

End of code.

So this is probably the most straightforward way to convert strings to symbols in your array(s) in Ruby. Make an array of strings then make a new variable and set the variable to an empty array. Then select each element in the first array you created with the ".each" method. Then use a block code to ".push" all of the elements in your new array and use ".intern or .to_sym" to convert all the elements to symbols.

Symbols are faster because they save more memory within your code and you can only use them once. Symbols are most commonly used for keys in hash which is great. I'm the not the best ruby programmer but this form of code helped me a lot.If anyone knows a better way please share and you can use this method for hash too!

  • 2
    The question was regarding hashes, not arrays. – Richard_G Aug 22 '16 at 12:02

If you would like vanilla ruby solution and as me do not have access to ActiveSupport here is deep symbolize solution (very similar to previous ones)

    def deep_convert(element)
      return element.collect { |e| deep_convert(e) } if element.is_a?(Array)
      return element.inject({}) { |sh,(k,v)| sh[k.to_sym] = deep_convert(v); sh } if element.is_a?(Hash)

Starting on Psych 3.0 you can add the symbolize_names: option

Psych.load("---\n foo: bar") # => {"foo"=>"bar"}

Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}

Note: if you have a lower Psych version than 3.0 symbolize_names: will be silently ignored.

My Ubuntu 18.04 includes it out of the box with ruby 2.5.1p57



def recursive_symbolize_keys(my_hash)
  case my_hash
  when Hash
      my_hash.map do |key, value|
  when Enumerable
    my_hash.map { |value| recursive_symbolize_keys(value) }





Hash#delete returns the value of the deleted key


Facets' Hash#deep_rekey is also a good option, especially:

  • if you find use for other sugar from facets in your project,
  • if you prefer code readability over cryptical one-liners.


require 'facets/hash/deep_rekey'
my_hash = YAML.load_file('yml').deep_rekey

In ruby I find this to be the most simple and easy to understand way to turn string keys in hashes to symbols :


For each key in the hash we call delete on it which removes it from the hash (also delete returns the value associated with the key that was deleted) and we immediately set this equal to the symbolized key.


Similar to previous solutions but written a bit differently.

  • This allows for a hash that is nested and/or has arrays.
  • Get conversion of keys to a string as a bonus.
  • Code does not mutate the hash been passed in.

    module HashUtils
      def symbolize_keys(hash)
        transformer_function = ->(key) { key.to_sym }
        transform_keys(hash, transformer_function)
      def stringify_keys(hash)
        transformer_function = ->(key) { key.to_s }
        transform_keys(hash, transformer_function)
      def transform_keys(obj, transformer_function)
        case obj
        when Array
          obj.map{|value| transform_keys(value, transformer_function)}
        when Hash
          obj.each_with_object({}) do |(key, value), hash|
            hash[transformer_function.call(key)] = transform_keys(value, transformer_function)

Your Answer

