Modules & idempotency
The unit of work that runs safely twice.
A module is Ansible’s unit of work — a small program that does one thing well: apt/yum/dnf install packages, copy and template manage files, service and systemd manage services, user manages accounts, and hundreds more. You do not write shell; you declare the desired state to a module and it figures out the commands. This is what makes Ansible readable and, crucially, idempotent.
# a module declares desired state; Ansible reports whether it changed anything$ ansible web -i inventory.ini -m apt -a "name=nginx state=present" --becomeweb1 | CHANGED => { "changed": true } # nginx was installed$ ansible web -i inventory.ini -m apt -a "name=nginx state=present" --becomeweb1 | SUCCESS => { "changed": false } # already present — nothing done
Idempotency is the whole point
Notice the second run says changed: false. A good module checks the current state and acts only if reality differs from what you declared, so running the same automation repeatedly is safe — it converges rather than piling up duplicate changes. This is the core promise of configuration management: describe the end state, run as often as you like, and the system settles there. It is also why you avoid the raw command/shell modules when a real module exists.