AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

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

- 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.

Performance Comparison

MethodSpeedReadabilityBest For
List in name:Fastest (single transaction)GoodSame state, same module
loop:Slower (one call per item)GoodDifferent states per package
with_items:Same as loop (legacy)OKLegacy 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

Browse all Ansible tutorials · AnsiblePilot Home