What is a Dry Run?
A dry run lets you see what changes Ansible would make — without actually changing anything. Use --check to simulate and --diff to see the exact differences.
# Dry run — show what would change
ansible-playbook playbook.yml --check
# Dry run with diff — show exact changes
ansible-playbook playbook.yml --check --diff
--check (Check Mode)
Check mode simulates the playbook run. Tasks report what they would do:
ansible-playbook deploy.yml --check
Output:
TASK [Install nginx] ***
changed: [web1] # Would install nginx (not actually installed)
TASK [Copy config] ***
changed: [web1] # Would copy the file (not actually copied)
TASK [Start nginx] ***
ok: [web1] # Already running, no change needed
Important Limitations
Not all modules support check mode. Modules that don't will either:
- Skip the task (with a warning)
- Run normally (ignoring check mode)
The command and shell modules always show "skipped" in check mode because Ansible can't predict their output:
TASK [Run migration script] ***
skipping: [web1] # Can't simulate command output
--diff (Diff Mode)
Shows the exact line-by-line differences for file changes:
ansible-playbook deploy.yml --diff
Output:
TASK [Deploy nginx config] ***
--- before: /etc/nginx/nginx.conf
+++ after: /tmp/nginx.conf.j2
@@ -1,5 +1,5 @@
server {
- listen 80;
+ listen 8080;
server_name example.com;
}
changed: [web1]
Combining --check and --diff
The most useful combination — see what would change and the exact differences:
ansible-playbook deploy.yml --check --diff
This is the recommended pre-deployment check:
# 1. Preview changes
ansible-playbook deploy.yml --check --diff
# 2. Review the output carefully
# 3. Apply for real
ansible-playbook deploy.yml
Per-Task Check Mode Control
Force a task to always run (even in check mode)
- name: Gather current state (always runs)
ansible.builtin.command: cat /opt/app/version.txt
register: current_version
check_mode: false # Runs even during --check
Force a task to always use check mode
- name: Verify config syntax (never changes)
ansible.builtin.command: nginx -t
check_mode: true # Always simulates, even without --check
Using ansible_check_mode Variable
- name: Run migration only in real mode
ansible.builtin.command: /opt/app/migrate.sh
when: not ansible_check_mode
- name: Show what would happen
ansible.builtin.debug:
msg: "Would run migration (skipped in check mode)"
when: ansible_check_mode
Practical Workflow
Safe Deployment Process
# Step 1: Lint the playbook
ansible-lint deploy.yml
# Step 2: Dry run with diff
ansible-playbook deploy.yml --check --diff -v
# Step 3: Deploy to staging
ansible-playbook deploy.yml -i staging -v
# Step 4: Verify staging
# Step 5: Deploy to production
ansible-playbook deploy.yml -i production -v
CI/CD Integration
# GitHub Actions example
jobs:
validate:
steps:
- name: Dry run
run: ansible-playbook deploy.yml --check --diff
deploy:
needs: validate
steps:
- name: Deploy
run: ansible-playbook deploy.yml
Tips
- Always dry-run before production —
--check --diffis your safety net - Not all modules support check mode —
command,shell,rawcan't simulate - Use
check_mode: falsefor data-gathering tasks that must run - Diff only works on file tasks —
template,copy,lineinfile, etc. - Combine with
--limitto dry-run against a single host first
Related Articles
- Ansible Tutorial for Beginners — Complete getting started guide
- How to Install Ansible — Installation on all platforms
- Ansible Training — Courses and certifications
- Ansible Dry Run — Test playbooks safely
- Ansible Facts — Gather system info
- Ansible Vault — Encrypt secrets
- Ansible Error Handling — Handle failures
Learn more safe automation practices in our 800+ tutorials on AnsibleByExample.