Agentless configuration management over SSH (or WinRM), running ordered tasks built from idempotent modules: “ensure this package is installed,” not “install this package.” There is no global state file and no whole-system diff. Ansible only touches what you tell it to touch.
Agentless plus SSH means it works on day zero against any Unix box that already accepts SSH. Nothing to bootstrap on the target, which is a major operational advantage when you inherit existing fleets, lab equipment, or bare-metal servers you don’t control end-to-end. The lack of a state file is both the freedom and the limitation. Freedom: no state corruption, no locking, no secrets-in-state, no concept of “drift” because nothing claims to be authoritative. Limitation: no whole-system view, no automatic deletion of things you removed from the playbook, no reliable preview of “what would this run change.” --check mode offers a dry run, but quality varies module by module, unlike Terraform’s first-class plan.
Two patterns dominate. Bootstrap workflow: provision a VM with Terraform, then hand off to Ansible to install packages, write config files, start services. Fleet operations: rolling restart 200 web servers, rotate a credential across a cluster, apply a kernel patch. The procedural model fits “do this everywhere, in this order.” App-level state can also flow through community modules (postgresql_query, grafana_dashboard, keycloak_realm), the same targets as Terraform providers but a different execution model.
Reach for it when the work is genuinely procedural, when you don’t want a state file, or when Ansible already runs your machines and adding Terraform is overhead. The idempotency contract lives in module quality: custom command: and shell: tasks break it instantly because they always report “changed,” so prefer real modules. Largely supplanted by NixOS-style declarative system config when you control the machine end-to-end and can build a system closure rather than mutating one in place.