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.

Related Articles

Ansible Playbook GuideAnsible Variables Guide

Performance 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

Browse all Ansible tutorials · AnsiblePilot Home