# Variables and Precedence — Ansible: Automate Servers with Playbooks

Source: https://www.geekswithgeeks.com/en/ansible/var-basics

> Define variables in several places and understand which one wins.

## Many places, one winner

Variables can come from the inventory, `group_vars/` and `host_vars/` files, a play's `vars:`, role defaults, facts, `register`ed results and the command line. When the same name appears in several places, Ansible follows a documented **precedence** order. Two useful rules: **role defaults** are the weakest, so they are easy to override; and **`-e` (extra vars)** on the command line beats almost everything, which makes it handy for one-off overrides.

## Same playbook, different hosts

Variables, facts and templates let one playbook configure many different hosts correctly.

![Four sources: inventory, vars, facts, templates.](assets/figures/ansible/section-3-map.svg) — Figure 3.1 — Inventory, vars, facts and templates.

## Override with -e, run

I ran the example below, where `env` defaults to `staging` in the play. The task guarded by `when: env == "production"` is skipped normally. With `-e env=production --tags prod`, the extra var wins and the task runs and prints its message.

```bash
ansible-playbook -i inventory.ini vars.yml -e env=production --tags prod
```

Output:

```
"msg": "prod only"
```

## The playbook used

The same file also demonstrates loops, `when`, `register` and tags in the next section.

```yaml
---
- hosts: web1
  gather_facts: false
  vars:
    packages: [git, curl, nginx]
    env: staging
  tasks:
    - name: Show packages with loop
      ansible.builtin.debug:
        msg: "install {{ item }}"
      loop: "{{ packages }}"
    - name: Only in production
      ansible.builtin.debug:
        msg: "prod only"
      when: env == "production"
      tags: [prod]
    - name: Register a result
      ansible.builtin.command: echo hello
      register: out
      changed_when: false
      tags: [info]
    - name: Show registered stdout
      ansible.builtin.debug:
        var: out.stdout
      tags: [info]
```

## Keep names clear and prefixed

Prefix role variables with the role name (`nginx_port`, not `port`) to avoid accidental clashes. Never use a variable name that is also an Ansible keyword.

**Quiz:** Which source usually overrides almost everything else?

- [ ] A comment in YAML
- [ ] Role defaults
- [x] -e extra vars on the command line
- [ ] The file name

*Answer:* -e extra vars on the command line. Extra vars have the highest precedence, which is useful for overrides and risky if overused.
