# Merge/Combine Inventory Variables with Defaults rather than override

**URL:** <https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701>\
**Category:** Ansible Project\
**Created:** [June 4, 2018, 1:37pm UTC](https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701 "2018-06-04T13:37:39Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![christoph.vogelsberg](https://avatars.discourse-cdn.com/v4/letter/c/2acd7d/32.png) [@christoph.vogelsberg](https://forum.ansible.com/u/christoph.vogelsberg)\
**Post date:** [June 4, 2018, 1:37pm UTC](https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701/1 "2018-06-04T13:37:39Z")

</div>

Hey folks,

the `defaults/main.yml` in a Role will be overridden in the precedence chain. In essence, as I understand, it is a dictionary that will be overlayed/merged/combined with sub-sequent variable settings (e.g. by inventory variables) [in the manner as described here](https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#combining-hashes-dictionaries). But I suspect, this isn’t done recursively.

_How can I achieve recursive combination of dictionaries in the defaults?_

I discovered that many definitions are flat, e.g.

`myapp_component1_feature1: defaultA myapp_component1_feature2: defaultB myapp_component2_feature1: defaultC myapp_component2_feature2: defaultD`

instead of

`myapp: component1: feature1: defaultA feature2: defaultB component2: feature1: defaultC feature2: defaultD`

The second schema is favorable not only for elegance but also if e.g. I would like to iterate over components of myapp or over features of a component with Jinja. However, when I want to use the defaults in e.g. an inventory file in a suggestive manner

`  
[www.example.com](http://www.example.com)  
vars:  
myapp:  
component1:  
feature2: myvalueB  
component2:  
feature1: myvalueC

`

The sub-dictionaries will be overridden instead of being combined. It will only contain the explicit elements.

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [June 6, 2018, 10:01am UTC](https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701/2 "2018-06-06T10:01:21Z")

</div>

That link to is a filter that you can use in your code to combine hashes/dictonaries and has nothing to on how Ansible overwrite/replace variables.

Default Ansible overwrite the whole variables in a predetermine order, variable precedence, that is documented here  
[http://docs.ansible.com/ansible/latest/user\_guide/playbooks\_variables.html#variable-precedence-where-should-i-put-a-variable](http://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)

Ansible has an option hash\_behavior(default is replace) that you can set to merge, it will then merge hashes/dictonaries instead of replacing them.

---

<div class="post-metadata">

**Author:** ![christoph.vogelsberg](https://avatars.discourse-cdn.com/v4/letter/c/2acd7d/32.png) [@christoph.vogelsberg](https://forum.ansible.com/u/christoph.vogelsberg)\
**Post date:** [June 6, 2018, 2:00pm UTC](https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701/3 "2018-06-06T14:00:46Z")

</div>

Hi Kai,

> Ansible has an option hash\_behavior(default is replace) that you can set  
> to merge, it will then merge hashes/dictonaries instead of replacing  
> them.

Unfortunately, [DEFAULT\_HASH\_BEHAVIOUR (Ansible Docs)](http://docs.ansible.com/ansible/latest/reference_appendices/config.html?highlight=hash_behaviour#default-hash-behaviour) states that it is not a recommended practice. But luckely, I found a way that seems to be pretty straight-forward:

role/default/main.yml

`

`myapp_defaults: component1: feature1: defaultA feature2: defaultB component2: feature1: defaultC feature2: defaultD`

`

role/vars/main.yml

`  
myapp\_vars: |  
{%- if myapp is defined and myapp is iterable -%}  
{{ myapp\_defaults | combine (myapp, recursive=True) }}  
{%- else -%}  
{{ myapp\_defaults }}  
{%- endif -%}

`

The usage in the role/tasks/xyz.yml then is e.g.

`

- name: Some task  
XXX:  
YYY: “{{ myapp\_vars.component2.feature1 }}”  
…  
…

`

Applying the role e.g. with play vars

`

# My Playbook

- name: setup MyApp  
vars:  
myapp:  
component2:  
feature1: “foo”  
feature2: “bar”  
tasks:
- include\_role:  
name: myapp

`

Variable precedence is important, e.g. the following wouldn’t work:

`

# My Playbook

- name: setup MyApp  
tasks:
- include\_role:  
name: myapp  
vars:  
myapp:  
component2: …  
…

`

since role/vars/main.yml is already read in when include\_vars are applied.

---

<div class="post-metadata">

**Author:** ![Max\_Bigras](https://avatars.discourse-cdn.com/v4/letter/m/f07891/32.png) [@Max\_Bigras](https://forum.ansible.com/u/Max_Bigras)\
**Post date:** [May 4, 2019, 9:04am UTC](https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701/4 "2019-05-04T09:04:17Z")

</div>

Hi christoph,

Was very excited to see your solution to this problem.  
I’ve been struggling to find a way to work around ansible replacing dictionaries.

Are you still using this approach?  
How has it been working for you?  
Have you made any changes?

---

<div class="post-metadata">

**Author:** ![Aravinda\_R](https://avatars.discourse-cdn.com/v4/letter/a/bbe5ce/32.png) [@Aravinda\_R](https://forum.ansible.com/u/Aravinda_R)\
**Post date:** [April 8, 2021, 10:59am UTC](https://forum.ansible.com/t/merge-combine-inventory-variables-with-defaults-rather-than-override/27701/5 "2021-04-08T10:59:36Z")

</div>

Hi Christoph,

I tried this with one of my Ansible work, looks like it does not work well if we have a nested dict. any suggestions ?
