Let's say I have two cookbooks, Foo and Bar. In cookbook Foo, attributes/default.rb contains the following:

default[:test] = [{:baz => 'A', :qux => 'B'}]

In cookbook B, I'd like to expand that array with another object (i.e. merge the two arrays): {:baz => 'C', :qux => 'D'}, ideally from within a recipe.

I tried to put the following Bar's recipe, or the attributes file:

default[:test] = [{:baz => 'C', :qux => 'D'}]

Expecting the two to get merged and result in:

node[:test] == [{:baz => 'A', :qux => 'B'}, {:baz => 'C', :qux => 'D'}]

But that is not what happens. Instead, only one of the two objects is contained in the array during a Chef-Solo run. I also tried with default.override and default.set with the same results. How can I merge the two arrays?


2 Answers 2


If you want to add individual hash elements to an array you can do it using the insertion operator << instead of the assignment operator =

In cookbook A

# Create the default attribute as an array
default[:test]=[{:baz => 'A', :qux => 'B'}]

In cookbook B

# Using array insertion on an existing array
default[:test] << {:baz => 'C', :qux => 'D'}

If the runlist order is not guaranteed to be A,B then you need to guard against trying to insert into an array which doesn't yet exist.

In cookbook A

default[:test] ||= []
default[:test] << {:baz => 'A', :qux => 'B'}

In cookbook B

default[:test] ||= []
default[:test] << {:baz => 'C', :qux => 'D'}

If you want to merge 2 arrays just use +=

# In cookbook A
default[:test]=[{:baz => 'A', :qux => 'B'}]

# In cookbook B
default[:test] += [ {:baz => 'C', :qux => 'D'}, {:baz => 'E', :qux => 'F'} ]

You can try using Chef's DeepMerge method from inside the second recipe like:

a = Chef::Mixin::DeepMerge.merge(node[:test], [ (new array here) ])

a will contain the deep-merged hashes!

  • That doesn't seem to work when I want to set node[:test] to the deeply merged array. Here's the exact code I'm running: Cookbook1/attributes/default.rb: default[:test] = [{:baz => 'A', :qux => 'B'}] Cookbook2/recipes/default.rb: a = Chef::Mixin::DeepMerge.merge(node[:test], [{:baz => 'C', :qux => 'D'}]) followed by node.override[:test] = a This however results in node[:test] being empty.
    – Joseph S.
    Mar 5, 2013 at 8:34
  • I proposed an edit to change from merge to deep_merge. If there are conflicts the value in the first "source" hash will win.
    – KCD
    Apr 9, 2015 at 2:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .