# Using a variable from one play across other plays

**URL:** <https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471>\
**Category:** Get Help\
**Created:** [March 3, 2026, 4:16pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471 "2026-03-03T16:16:02Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bryonadams](https://avatars.discourse-cdn.com/v4/letter/b/67e7ee/32.png) [@bryonadams](https://forum.ansible.com/u/bryonadams)\
**Post date:** [March 3, 2026, 4:16pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/1 "2026-03-03T16:16:02Z")

</div>

I’m getting my `ansible_become_pass` from my Bitwarden vault successfully, but I want to re-use it across plays within the playbook. To do this, I wanted to set it like so, but I think I’m trying to fetch it incorrectly. I tried also to set `delegate_facts: true` but it did not work.

```auto
- name: Testing Bitwarden collection
  hosts: ansible_test_vm
  tasks:

    - name: Get password for "badmin - Lab User" from Bitwarden
      ansible.builtin.set_fact:
        bw_data: >-
          {{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
        cacheable: true
      delegate_to: localhost

    - name: Check if `/etc/profile.d/ps1.sh` exists
      ansible.builtin.stat:
        path: /etc/profile.d/ps1.sh
      become: true
      register: stat_ps1_sh

  vars:
    ansible_become_pass: "{{ hostvars['localhost']['bw_data'] }}"

```

The error I receive is:

```auto
TASK [Gathering Facts] ************************************************************************************************************
fatal: [ansible]: FAILED! => {"msg": "The field 'become_pass' has an invalid value, which includes an undefined variable.. 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'bw_data'"}

```

Trying to call the variable this way causes Ansible to complain that the variable is empty.

```auto
  vars:
    ansible_become_pass: "{{ bw_data }}"

```

like so:

```auto
fatal: [ansible]: FAILED! => {"msg": "The field 'become_pass' has an invalid value, which includes an undefined variable.. 'bw_data' is undefined"}

```

I had this working prior but I wanted to try delegating the play instead of running in a different host section so it’s a shorter file. Really just playing around to be honest. Working playbook below:

```auto
- name: Testing Bitwarden collection
  hosts: localhost
  tasks:

    - name: 'Get password for "badmin - Lab User" from Bitwarden'
      ansible.builtin.set_fact:
        bw_data: >-
          {{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
        cacheable: true

- name: Use Bitwarden pass from task
  hosts: ansible_test_vm
  tasks:

    - name: Check if `/etc/profile.d/ps1.sh` exists
      ansible.builtin.stat:
        path: /etc/profile.d/ps1.sh
      become: true
      register: stat_ps1_sh

  vars:
    ansible_become_pass: "{{ hostvars['localhost']['bw_data'] }}"

```

How do I call this variable correctly, or is there a better way to go about this? I’m fine using the second (working) method if that’s what I’m meant to do.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [March 3, 2026, 4:27pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/2 "2026-03-03T16:27:27Z")

</div>

short:  
you have the correct way

long:  
Ansible has 2 variable scopes, play objects and hosts, play objects variables are inherited only by other play objects contained in the scope defined (think functions and embeded functions). Since plays are at the same level, not contained in other plays, you cannot pass variables from one play to the other.

Host scope is sustained through the run and accessible via the `hostvars` variable, so variables persist across plays within the same run, this is the proper way to ‘persist’ variables across plays.

Your first attempt is failing because while you delegate execution to `localhost` you do not `delegate_facts` to it, so the facts are applied to the ‘current host’ aka `inventory_hostname`, do that and both ways 'will work’TM.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [March 3, 2026, 5:00pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/3 "2026-03-03T17:00:39Z")

</div>

When I am creating playbooks, I try to avoid using hostvars - I consider this an internal structure of ansible.  
Here is my approach to do what you are trying to do:

```yaml
---
- name: Playbook with all shared variables (does not do anything)
  hosts: all
  gather_facts: false
  vars: &shared_playbook_variables
    bitwarden_password: "{{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}"
    bitwarden_password_for_current_host: "{{ lookup('community.general.bitwarden', ansible_hostname, field='password')[0] }}"
    ansible_become_pass: "{{ bitwarden_password }}"
  tasks: []

- name: First playbook
  hosts: all
  gather_facts: false
  vars:
    <<: *shared_playbook_variables
  tasks:
    - name: Simple debug for static variable
      ansible.builtin.debug:
        var: ansible_become_pass
    - name: Debug for variable that depends on the ansible hostname
      ansible.builtin.debug:
        var: bitwarden_password_for_current_host

- name: Second playbook
  hosts: all
  gather_facts: false
  vars:
    <<: *shared_playbook_variables
  tasks:
    - name: Simple debug for static variable
      ansible.builtin.debug:
        var: ansible_become_pass
    - name: Debug for variable that depends on the ansible hostname
      ansible.builtin.debug:
        var: bitwarden_password_for_current_host

```

Ansible playbooks are yaml files, so yaml anchoring can be used. Here is an explanation from bitbucker [YAML anchors | Bitbucket Cloud | Atlassian Support](https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/).

In playbook above there are two variables - one is static `bitwarden_password` - we get the password only once, another one bitwarden\_password\_for\_current\_host depends on host.  
First static variable, will not change from one place to another, but ansible will anyway get it for the second (and third time) because of its lazy evaluations. But this is a good thing, because we can use this feature in “dynamic” variable `bitwarden_password_for_current_host` - there is`ansible_hostname` magic variable that will be filled on each run with correct info. So for each host there will be correct call to lookup plugin (and correct password for the host).

---

<div class="post-metadata">

**Author:** ![bryonadams](https://avatars.discourse-cdn.com/v4/letter/b/67e7ee/32.png) [@bryonadams](https://forum.ansible.com/u/bryonadams)\
**Post date:** [March 3, 2026, 5:01pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/4 "2026-03-03T17:01:01Z")

</div>

So maybe I’m missing something else or have a typo I don’t see? I tried setting `delegate_facts: true` on the play where I get the password from Bitwarden but that doesn’t make it to the `ansible_become_pass` variable.

```auto
    - name: Get password for "badmin - Lab User" from Bitwarden
      ansible.builtin.set_fact:
        bw_data: >-
          {{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
        cacheable: true
      delegate_to: localhost
      delegate_facts: true

    - name: Test variable
      ansible.builtin.debug:
        msg: "{{ hostvars['localhost']['bw_data'] }}"

  vars:
    ansible_become_pass: "{{ hostvars['localhost']['bw_data'] }}"

```

I print the expected value in the test print statement when I run it (cheated by commenting out the `ansible_become_pass` to test), but I get the same error as before when running the playbook.

```auto
fatal: [ansible]: FAILED! => {"msg": "The field 'become_pass' has an invalid value, which includes an undefined variable.. 'ansible.vars.hostvars.HostVarsVars object' has no attribute 'bw_data'"}

```

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [March 3, 2026, 5:05pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/5 "2026-03-03T17:05:35Z")

</div>

> [@bcoca](#):
>
> Ansible has 2 variable scopes

There are of course different definitions of what scope is.  
Don’t you thing that example above demonstrates that there is also a “file” scope in ansible (or yaml)?

---

<div class="post-metadata">

**Author:** ![bryonadams](https://avatars.discourse-cdn.com/v4/letter/b/67e7ee/32.png) [@bryonadams](https://forum.ansible.com/u/bryonadams)\
**Post date:** [March 3, 2026, 6:09pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/6 "2026-03-03T18:09:01Z")

</div>

Hi kks, would each playbook be a separate .yaml file and I would call them when I run everything, or is this all in one file? I’ll give that method a go too, I like the idea of using ansible hosts for a variable when searching for a password.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [March 3, 2026, 6:20pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/7 "2026-03-03T18:20:45Z")

</div>

no, there is no ‘file’ scope, as you can have multiple files per run `ansible-playbook play1.yml play2.yml` the host scope is ‘per run’ as i mentioned before, the files are not relevant for scope as much as the contained playbook objects are, the scope would be the same in the run if the plays were defined in the same file or in different files.

What you are doing with YAML is pre generating a copy of the variables with YAML anchors, this is transparent to Ansible itself, this is not keeping variables in ‘file scope’ but using a property of YAML to make several copies of the same variables.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [March 3, 2026, 6:40pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/8 "2026-03-03T18:40:11Z")

</div>

> [@bryonadams](#):
>
> would each playbook be a separate .yaml

in my example all the plays should be in one file.

In order to make this example work for several playbooks files you can add variable to run:

```bash
ansible-playbook playbook1.yml playbook2.yml --extra-vars "@variables.yaml"

```

Variables file should look something like this:

```yaml
bitwarden_password: "{{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}"
bitwarden_password_for_current_host: "{{ lookup('community.general.bitwarden', ansible_hostname, field='password')[0] }}"
ansible_become_pass: "{{ bitwarden_password }}"

```

Similarly this can be archived with inventory files, just set variables you need for group “all”. Inventory can span across playbook runs.  
Do not worry to set variables to something that seems undefined, ansible will **only** read and evaluate variables when they are **needed**. Basically everywhere you can add variable:

```yaml
this_variable_is_never_used: put here whatevery, just valid yaml syntax, this will not have any influence for playbook run

```

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [March 3, 2026, 7:00pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/9 "2026-03-03T19:00:32Z")

</div>

It’s failing before `set_fact` even runs. To fix, you could do any of the following:

- set `vars` on the block-level (instead of the whole play)
- set `gather_facts: False` on the play if you don’t need to gather facts or
- use `| default(omit)` in the ansible\_become\_pass

You’ll also need to use `delegate_facts` with `set_fact` for `"{{ hostvars['localhost']['bw_data'] }}"` to work.

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [March 3, 2026, 8:07pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/10 "2026-03-03T20:07:05Z")

</div>

I’ve opened a possible fix so the undefined variable set on the play won’t be a problem, as long as gather\_facts isn’t using a become plugin [Only set become\_ options on PlayContext if the task uses become by s-hertel · Pull Request #86618 · ansible/ansible · GitHub](https://github.com/ansible/ansible/pull/86618).

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [March 4, 2026, 4:06pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/11 "2026-03-04T16:06:52Z")

</div>

In AWX, we “use” (feels more like “abuse”) [`ansible.builtin.set_stats`](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/set_stats_module.html#ansible-builtin-set-stats-module-define-and-display-stats-for-the-current-ansible-run) to pass [computed values](https://docs.ansible.com/projects/awx/en/24.6.1/userguide/workflows.html#extra-variables) from one job to a downstream job in the same [workflow](https://docs.ansible.com/projects/awx/en/24.6.1/userguide/workflows.html#workflows). This seems like a related thing, but I’ve not seen anything that allows tasks to see job “stats”. Rather this is an extra “thing” that AWX does outside of plays/playbooks.

Ignoring the obvious “don’t set\_stats secret values”, would someone who know how these things actually work care to compare and contrast facts as facts, facts as vars, and stats?

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [March 4, 2026, 4:13pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/12 "2026-03-04T16:13:12Z")

</div>

set\_stats was created specifically for passing variables to awx workflos. But we also added the ability to ‘view’ stats you can do that with the default callback [ansible.builtin.default callback – default Ansible screen output — Ansible Community Documentation](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/default_callback.html#parameter-show_custom_stats).

---

<div class="post-metadata">

**Author:** ![bryonadams](https://avatars.discourse-cdn.com/v4/letter/b/67e7ee/32.png) [@bryonadams](https://forum.ansible.com/u/bryonadams)\
**Post date:** [March 5, 2026, 5:18pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/13 "2026-03-05T17:18:58Z")

</div>

Hey this worked great! It felt really slow but I might need to debug that more. The bitwarden plugin is known to be pretty slow but I was only expecting initial slowness during the lookup.

I’m unsure if I’m understanding anchoring correctly. I understand that we’re anchoring our variables up top, then referencing them within a subsequent play via `<<: *shared_playbook_variables`. We’re not running the lookup from Bitwarden again, right? The Bitbucket doc says `<<:` is overriding things, but I think that means we’re overriding with what we already looked up.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [March 5, 2026, 5:48pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/14 "2026-03-05T17:48:58Z")

</div>

> [@bryonadams](#):
>
> felt really slow

> [@bryonadams](#):
>
> We’re not running the lookup from Bitwarden again, right?

unfortunately this is exactly what is happening, everytime ansible reads a variable that depends on that lookup, ansible will run the lookup again - this is a lazy nature of ansible. One way to not do lazy evaluations is to use set\_fact plugin.

> [@bryonadams](#):
>
> I’m unsure if I’m understanding anchoring correctly.

Ancoring is yaml feature, not ansible, from ansible point of view you had this variable definition typed several times. And this can be used to your advantage! You can “copy” any yaml content this way, here is an example for an action that is copied across several playbooks.

```yaml
---
- name: Playbook with all shared variables (does not do anything)
  hosts: all
  gather_facts: false
  tasks:
    - &set_fact_bitwarden
      name: Get password for "badmin - Lab User" from Bitwarden
      ansible.builtin.set_fact:
        bw_data: >-
          {{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
      delegate_to: localhost

- name: First playbook
  hosts: all
  gather_facts: false
  tasks:
    - *set_fact_bitwarden
      # This will copy the set_fact action from above, consider is copied verbatim from the playbook above, you can use it in many playbooks.

    - name: Print bw_data
      ansible.builtin.debug:
        var: bw_data

- name: Second playbook
  hosts: all
  gather_facts: false
  tasks:
    - *set_fact_bitwarden

    - name: Print bw_data
      ansible.builtin.debug:
        var: bw_data

```

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [March 5, 2026, 5:49pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/15 "2026-03-05T17:49:06Z")

</div>

The YAML anchoring happens BEFORE any execution or templating on the Ansible side, that is basically the same as writing YAML, it would result in the same thing as you manually copying and pasting the entry.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [March 5, 2026, 5:52pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/16 "2026-03-05T17:52:28Z")

</div>

> [@bryonadams](#):
>
> Bitbucket doc says `<<:` is overriding things

This is map merging, see here

> **[Learn YAML in Y Minutes](https://learnxinyminutes.com/yaml/)**

Whole document is worth reading, but this fragment is most relevent in this case

```yaml
# Anchors can be used to duplicate/inherit properties
base: &base
  name: Everyone has same name

# The expression << is called 'Merge Key Language-Independent Type'. It is used to
# indicate that all the keys of one or more specified maps should be inserted
# into the current map.
# NOTE: If key already exists alias will not be merged
foo:
  <<: *base # doesn't merge the anchor
  age: 10
  name: John
bar:
  <<: *base # base anchor will be merged
  age: 20

```

---

<div class="post-metadata">

**Author:** ![bryonadams](https://avatars.discourse-cdn.com/v4/letter/b/67e7ee/32.png) [@bryonadams](https://forum.ansible.com/u/bryonadams)\
**Post date:** [March 5, 2026, 6:07pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/17 "2026-03-05T18:07:46Z")

</div>

That’s what I was trying prior with the hostvars, but unfortunately I hit a snag block with my second attempt using delegation instead of distinct plays.

While I really like what you suggested, because the Bitwarden plugin is so slow, it’s a bit like watching paint dry now.

edit, I totally misread your new code block, let me give that a try

---

<div class="post-metadata">

**Author:** ![bryonadams](https://avatars.discourse-cdn.com/v4/letter/b/67e7ee/32.png) [@bryonadams](https://forum.ansible.com/u/bryonadams)\
**Post date:** [March 5, 2026, 6:50pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/18 "2026-03-05T18:50:38Z")

</div>

So this new way it still does the lookup at the start of each play, but not for each task (I omitted some tasks below). That’s intended, but much more bearable and I suspect this scales well if I’m using a variable for the key I look up (such as the host name in your example)?

```auto
---
- name: Testing Bitwarden lookups
  hosts: localhost
  gather_facts: false
  tasks:

    - &set_fact_bitwarden
      name: Get Bitwarden password for badmin lab user
      ansible.builtin.set_fact:
        ansible_become_pass: >-
          {{ lookup('community.general.bitwarden', 'badmin - Lab User', field='password')[0] }}
        delgate_to: localhost

- name: Test using Bitwarden varaible
  hosts: ansible
  gather_facts: false
  tasks:
    - *set_fact_bitwarden

    - name: Check if `/etc/profile.d/ps1.sh` exists
      ansible.builtin.stat:
        path: /etc/profile.d/ps1.sh
      become: true
      register: stat_ps1_sh

```

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [March 5, 2026, 8:21pm UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/19 "2026-03-05T20:21:58Z")

</div>

> [@bryonadams](#):
>
> key I look up (such as the host name in your example)?

Yes that will work with hostnames as variables in set fact. Just bear in mind that set\_fact “fixes” variable value so if one of the variables password depends on changed password will not be recalculated

---

<div class="post-metadata">

**Author:** ![bartowl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bartowl/32/7029_2.png) [@bartowl](https://forum.ansible.com/u/bartowl)\
**Post date:** [March 10, 2026, 6:02am UTC](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471/20 "2026-03-10T06:02:54Z")

</div>

Hmm, why not add a play at the very top with hosts: all, a single task set\_facts from lookup but with run\_once true? This would call the task just once for a random host (typically first) without really connecting to it (as this is set\_facts). Due to run\_once it will set a host-bound variable for all hosts targeted by the inventory, so all hosts in this example. In AWX you might consider using credentials for that, as injectors allow specifying hostvars and environment variables…

[Next page](https://forum.ansible.com/t/using-a-variable-from-one-play-across-other-plays/45471.md?page=2)
