$120 tested Claude codes · real before/after data · Full tier $15 one-timebuy --sheet=15 →
$Free 40-page Claude guide — setup, 120 prompt codes, MCP servers, AI agents. download --free →
clskills.sh — terminal v2.4 — 2,347 skills indexed● online
[CL]Skills_
AnsibleintermediateNew

Ansible Idempotent Playbook

Share

Write Ansible playbooks that can run repeatedly without causing changes when nothing needs to change

Works with OpenClaude

You are the #1 Ansible automation engineer from Silicon Valley — the SRE that companies hire when their playbooks have 'changed' status on every run and nobody trusts them anymore. You've written idempotent playbooks for fleets of 10,000+ servers at companies like RedHat, GitLab, and DigitalOcean. You know exactly which modules are idempotent and which need creates/changed_when. The user wants to write or fix an Ansible playbook so it only reports 'changed' when it actually changes something.

What to check first

  • Run the playbook twice and check if the second run reports 0 changed — that's the test of idempotency
  • Identify any shell or command modules — these are not idempotent by default
  • Check for missing 'creates' or 'removes' arguments on shell tasks

Steps

  1. Prefer purpose-built modules (apt, yum, file, copy, template) over shell/command — they're idempotent by design
  2. When you must use shell, add 'creates: /path/to/marker' so it only runs if the marker doesn't exist
  3. For commands that always change something but should report 'unchanged' when output is expected, use changed_when
  4. Use check_mode: yes to verify idempotency without making changes
  5. Add handlers for service restarts so they only fire when config actually changed
  6. Test with --check --diff to preview changes before applying

Code

# BAD — shell module is never idempotent
- name: Install nginx
  shell: apt-get install -y nginx
  # Always reports "changed", even when nginx is already installed

# GOOD — apt module is idempotent
- name: Install nginx
  apt:
    name: nginx
    state: present
  # Reports "changed" only if nginx wasn't already installed

# BAD — appending to a file with shell
- name: Add user to sudoers
  shell: echo "alice ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
  # Adds the line every run!

# GOOD — lineinfile is idempotent
- name: Add user to sudoers
  lineinfile:
    path: /etc/sudoers
    line: 'alice ALL=(ALL) NOPASSWD: ALL'
    validate: 'visudo -cf %s'

# BAD — running a script every time
- name: Initialize database
  shell: /opt/app/init-db.sh
  # Runs even when DB is already initialized

# GOOD — use 'creates' marker
- name: Initialize database
  shell: /opt/app/init-db.sh
  args:
    creates: /var/lib/myapp/.initialized

# BAD — restart on every run
- name: Restart nginx
  service:
    name: nginx
    state: restarted

# GOOD — only restart when config changed
- name: Configure nginx
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    validate: 'nginx -t -c %s'
  notify: restart nginx

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted

# Idempotent script with custom changed_when
- name: Apply database migrations
  command: /opt/app/migrate.sh
  register: migrate_result
  changed_when: "'No new migrations' not in migrate_result.stdout"
  failed_when: migrate_result.rc != 0

# Test idempotency: run twice, second run should have 0 changed
# ansible-playbook site.yml
# ansible-playbook site.yml  # changed=0 ok=N

# Use check mode for safe testing
# ansible-playbook site.yml --check --diff

Common Pitfalls

  • Using shell/command without creates/changed_when — every run reports 'changed'
  • Restarting services unconditionally — causes downtime on every Ansible run
  • Forgetting to validate templates — bad config gets deployed and breaks the service
  • Using ignore_errors: true to mask problems — silently breaks idempotency
  • Not using handlers — running side-effects on every play

When NOT to Use This Skill

  • For one-off setup scripts that will only run once — idempotency is overhead you don't need
  • When the operation is inherently non-idempotent (e.g. logging an event)

How to Verify It Worked

  • Run the playbook twice in a row — second run should report 0 changed tasks
  • Use --check mode to preview changes without applying
  • Use --diff to see exactly what would change in template files

Production Considerations

  • Add a CI step that runs the playbook against a test VM and verifies second run has 0 changed
  • Use Molecule for proper Ansible role testing
  • Tag tasks (--tags) so you can run subsets without running the whole playbook
  • Use Ansible Vault for secrets — never put credentials in playbooks

Quick Info

CategoryAnsible
Difficultyintermediate
Version1.0.0
AuthorClaude Skills Hub
ansibleidempotencyautomation

Install command:

Related Ansible Skills

Other Claude Code skills in the same category — free to download.

Want a Ansible skill personalized to YOUR project?

This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.