# Groups in Parallel, hosts in serial

**URL:** <https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131>\
**Category:** Get Help\
**Tags:** inventory\
**Created:** [August 5, 2026, 1:58pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131 "2026-08-05T13:58:17Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![phessler](https://avatars.discourse-cdn.com/v4/letter/p/fbc32d/32.png) [@phessler](https://forum.ansible.com/u/phessler)\
**Post date:** [August 5, 2026, 1:58pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/1 "2026-08-05T13:58:17Z")

</div>

Hi All,

I have a relatively standard HA deployment, where I have several regions each with their own load balancer and several hosts in each region.

What I want to do is be able to do a normal ansible-playbook run, and have it run all regions in parallel, but each host within a region serially. Using the below (fake) inventory, paris01, fra01, and lon01 start at the same time. after paris01 finishes, paris02 doesn’t care what the state of fra\* and lon\* are, but paris03 won’t start until paris02 is done.

I’ve found a lot of queries about this over the years, but no satisfactory answers. I am aware of setting serial:1 and then limiting my playbook execution to specific inventory groups, but would prefer not to do that (as it is annoying).

[paris]  
paris01  
paris02  
paris03

[frankfurt]  
fra01  
fra02  
fra03  
fra04

[london]  
lon01  
lon02  
lon03  
lon04  
lon05  
lon06

---

<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:** [August 5, 2026, 4:26pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/2 "2026-08-05T16:26:02Z")

</div>

You aren’t going to like this, but

```sh
$ params=( do_region.yml -v -D -i fake-inventory.ini )
$ ansible-playbook "${params[@]}" --limit paris & \
ansible-playbook "${params[@]}" --limit frankfurt & \
ansible-playbook "${params[@]}" --limit london &

```

---

<div class="post-metadata">

**Author:** ![phessler](https://avatars.discourse-cdn.com/v4/letter/p/fbc32d/32.png) [@phessler](https://forum.ansible.com/u/phessler)\
**Post date:** [August 5, 2026, 4:59pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/3 "2026-08-05T16:59:06Z")

</div>

You’re right, that is exactly what I don’t want to do. Is that the only option?

---

<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:** [August 5, 2026, 6:13pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/4 "2026-08-05T18:13:10Z")

</div>

No; another option would be a playbook with multiple plays. The first play would select the first host from each of the three regional groups, dynamically create a group containing those three hosts, and likewise for each of the N-th hosts.

Then [hand-waving here] you would run your “real” play successively on each of these groups of hosts. Somehow.

Assuming it’s possible and you work out the details, you’ll end up with something rather complicated to read but which functionally is equivalent to running three `ansible-playbook` instances (as per my prior post). You could stand up AWX or AAP and schedule three jobs, one per region, which is great if you need the functionality that AWX/AAP provide for additional things. But it’s a lot of stuff to set up if the only point is to avoid a half-dozen lines of bash.

I can see the appeal of expressing that functionality in one glorious YAML expression. But the permutations on hosts, groups, and play strategies is already complicated enough. If you made `ansible-playbook` “recursively parallel” so to speak, I fear the complexity would far outweigh the practical benefits.

Not to rule out the possibility that some obscure combination of Ansible options that I haven’t thought of might provide the functionality you’re after, but I’m skeptical. Maybe a custom `strategy` plugin could pull it off? 🤷

---

<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:** [August 5, 2026, 6:31pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/5 "2026-08-05T18:31:02Z")

</div>

Another option might be to write ansible strategy plugin

> **[Strategy plugins — Ansible Community Documentation](https://docs.ansible.com/projects/ansible/latest/plugins/strategy.html)**

---

<div class="post-metadata">

**Author:** ![phessler](https://avatars.discourse-cdn.com/v4/letter/p/fbc32d/32.png) [@phessler](https://forum.ansible.com/u/phessler)\
**Post date:** [August 5, 2026, 6:35pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/6 "2026-08-05T18:35:54Z")

</div>

thanks a lot @kks and @utoddl, a custom strategy might end up doing the trick.

Thankfully right now it’s only 2 hosts each spread over two regions, so serial:1 is acceptable for now. But the medium-term goal is something like 40 regions, which gets quite intensive.

---

<div class="post-metadata">

**Author:** ![bvitnik](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bvitnik/32/4132_2.png) [@bvitnik](https://forum.ansible.com/u/bvitnik)\
**Post date:** [August 5, 2026, 6:51pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/7 "2026-08-05T18:51:25Z")

</div>

Is the play(book) identical for all of the host groups? If that is the case, or if it can be made like that, there is a trick with `throttle` task level keyword that I used to achieve this. Now, in my defense, it was implemented for a single task only. I’m not sure if it will work as expected if applied to a block of tasks. Also, it requires some clever ordering of hosts in the inventory.

---

<div class="post-metadata">

**Author:** ![phessler](https://avatars.discourse-cdn.com/v4/letter/p/fbc32d/32.png) [@phessler](https://forum.ansible.com/u/phessler)\
**Post date:** [August 6, 2026, 10:17am UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/8 "2026-08-06T10:17:11Z")

</div>

the playbook is not guaranteed to be the same. the hosts currently have 2-4 services loaded, which is defined with inventory groups. however, each group does have the same playbooks applied to them.

throttle does seem to work in handlers, which is where I mostly want to use them, so I’ll experiment there. Seems I can go to “all parallel, but throttle service restarts”, which is quite acceptable to me performance wise.

---

<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:** [August 6, 2026, 10:40am UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/9 "2026-08-06T10:40:55Z")

</div>

> [@phessler](#):
>
> Seems I can go to “all parallel, but throttle service restarts”, which is quite acceptable to me performance wise.

Do you have to use handler? You can you `when:` and run it only when something actually changed. Looks like to you have two strategies you want to combine in one playbook run - free and throttle. I think you can have several plays in one playbook with different configurations - that might solve it for you.

---

<div class="post-metadata">

**Author:** ![phessler](https://avatars.discourse-cdn.com/v4/letter/p/fbc32d/32.png) [@phessler](https://forum.ansible.com/u/phessler)\
**Post date:** [August 6, 2026, 10:49am UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/10 "2026-08-06T10:49:58Z")

</div>

I originally tried when: , but that would only trigger when the last file for that service changed. If I have 4 files, and the first 3 change but the last one doesn’t, then when: won’t trigger for me. notify/handler does trigger in that situation.

---

<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:** [August 6, 2026, 12:49pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/11 "2026-08-06T12:49:43Z")

</div>

We have a case where a handler just does a `set_fact` of `service_x_requires_deferred_restart`. The service isn’t restarted until after several other plays. Not a recommendation; just noting a possibility.

---

<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:** [August 6, 2026, 1:01pm UTC](https://forum.ansible.com/t/groups-in-parallel-hosts-in-serial/46131/12 "2026-08-06T13:01:26Z")

</div>

I was also thinking somewhere along those lines - this might be the third use case where set\_fact can be useful.
