How to Install Multiple Packages in Ansible (One Task)
By Luca Berton · Published 2024-01-01 · Category: installation
How to install multiple packages in a single Ansible task using apt, dnf, yum, and package modules. Efficient package management with lists and loops.
How to Install Multiple Packages in Ansible (One Task)
Installing packages one at a time is slow. Here's how to install many packages efficiently in a single task.
See also: Ansible apt Module: Install, Remove & Manage Packages on Debian/Ubuntu
List of Packages (Recommended)
- name: Install required packages
ansible.builtin.apt:
name:
- nginx
- postgresql-client
- python3-pip
- htop
- tmux
- curl
- jq
state: present
update_cache: true
cache_valid_time: 3600
This runs a single apt transaction — much faster than looping.
Using a Variable
vars:
base_packages:
- vim
- curl
- wget
- htop
- tree
app_packages:
- nginx
- python3
- python3-venv
- redis-server
tasks:
- name: Install all packages
ansible.builtin.apt:
name: "{{ base_packages + app_packages }}"
state: present
See also: Ansible on Alpine Linux 3.20: Container Engine Setup Complete Guide
Cross-Platform Package Installation
# Using the generic package module
- name: Install packages (any distro)
ansible.builtin.package:
name: "{{ item }}"
state: present
loop:
- git
- curl
- vim
# OS-specific packages
- name: Install on Debian/Ubuntu
ansible.builtin.apt:
name: ["nginx", "python3-pip", "libpq-dev"]
state: present
when: ansible_os_family == "Debian"
- name: Install on RHEL/Fedora
ansible.builtin.dnf:
name: ["nginx", "python3-pip", "postgresql-devel"]
state: present
when: ansible_os_family == "RedHat"
Install Specific Versions
- name: Install specific versions
ansible.builtin.apt:
name:
- nginx=1.24.*
- postgresql-16
- redis-server=7:7.0.*
state: present
See also: Ansible on Amazon Linux 2023: Container Engine Setup Complete Guide
Why Not Use Loop?
# ❌ SLOW — runs apt separately for each package
- name: Install packages (slow)
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis
# ✅ FAST — single apt transaction
- name: Install packages (fast)
ansible.builtin.apt:
name: [nginx, postgresql, redis]
state: present
The list approach runs one apt install nginx postgresql redis command. The loop runs three separate commands.
FAQ
How do I install multiple packages in one Ansible task?
Pass a list to the name parameter: name: [nginx, python3, curl]. The apt, dnf, and yum modules handle lists natively, installing all packages in a single transaction.
Is it faster to use a list or a loop?
A list is significantly faster. It runs one package manager command instead of one per package. Use lists whenever possible.
How do I install packages on both Debian and RHEL?
Use ansible.builtin.package (generic) for common packages, or use when: ansible_os_family conditionals with apt and dnf for OS-specific package names.
Related Articles
• Ansible Playbook Guide • Ansible Variables GuidePerformance Comparison
| Method | Speed | Readability | Best For |
|---|---|---|---|
| List in name: | Fastest (single transaction) | Good | Same state, same module |
| loop: | Slower (one call per item) | Good | Different states per package |
| with_items: | Same as loop (legacy) | OK | Legacy playbooks |
Cross-Platform Package Installation
- name: Install packages on any OS
hosts: all
become: true
tasks:
- name: Install common packages (RHEL/CentOS/AlmaLinux)
ansible.builtin.dnf:
name:
- vim-enhanced
- git
- curl
- wget
- tmux
- htop
state: present
when: ansible_os_family == "RedHat"
- name: Install common packages (Debian/Ubuntu)
ansible.builtin.apt:
name:
- vim
- git
- curl
- wget
- tmux
- htop
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install packages using generic module
ansible.builtin.package:
name:
- git
- curl
- wget
state: present
Using Variables for Package Lists
- name: Install from variable list
hosts: all
become: true
vars:
base_packages:
- git
- curl
- vim
web_packages:
- nginx
- certbot
all_packages: "{{ base_packages + web_packages }}"
tasks:
- name: Install all packages
ansible.builtin.package:
name: "{{ all_packages }}"
state: present
FAQ
Is it faster to pass a list or use a loop?
Passing a list to the name: parameter is significantly faster. The package manager handles all packages in one transaction instead of making separate calls per package.
Can I mix install and remove in one task?
No. Each task has one state:. Use separate tasks for state: present and state: absent.
Does ansible.builtin.package work on all distributions?
Yes, it auto-detects the package manager (apt, dnf, yum, zypper, etc.). However, package names may differ across distributions (e.g., vim-enhanced on RHEL vs vim on Debian).
Category: installation