After you write an Ansible playbook, the next question is usually: how do I run it safely? A normal run is simple, but real usage often needs more control—checking syntax first, limiting the target hosts, previewing changes, showing diffs, running only tagged tasks, or using ansible-navigator with an execution environment.
This guide shows the commands you will actually use while testing and running playbooks, starting with a simple run and then adding safer options such as --syntax-check, --list-hosts, --check, --diff, --limit, and --tags.
Read playbook structure and YAML syntax first. This page does not teach playbook anatomy, tag design, or ansible-navigator.yml settings—those live in dedicated guides linked below.
Tested on: Rocky Linux 10.2 (Red Quartz); kernel 6.12.0-211.16.1.el10_2.0.1.x86_64; ansible-core 2.16.16; ansible-navigator 26.6.0.
~/ansible-project, inventory group lab, and playbooks in playbooks/. Use your own host names and paths if yours differ.
| Tool | Best for |
|---|---|
ansible-playbook |
Simple local playbook execution |
ansible-playbook --check --diff |
Previewing changes safely |
ansible-playbook --limit |
Restricting a run to selected hosts |
ansible-playbook --tags |
Running selected tagged tasks |
ansible-navigator run |
TUI or stdout execution and EE-based workflows |
ansible-navigator run --mode stdout |
Script-friendly navigator output |
For a new playbook, do not jump straight to a full run on every host. First confirm that Ansible can parse the file, then confirm which hosts match, then preview the change, then run on one host or a small group. Once that works, run the full playbook.
What Happens When You Run an Ansible Playbook?
When you run a playbook, Ansible:
- Loads ansible.cfg from the project directory
- Resolves inventory (from
-ior config) - Parses the playbook YAML and builds plays and tasks
- Connects to each matched host over SSH
- Runs tasks in order and collects results
- Prints per-task status and a
PLAY RECAPsummary
Failures on a host stop further tasks on that host unless you use rescue blocks (see block and rescue).
ansible-playbook vs ansible-navigator
ansible-playbook |
ansible-navigator run |
|
|---|---|---|
| Runs on | Control node (local ansible-core) | Wraps playbook runs; may use execution environment (container) |
| UI | Plain terminal output | Interactive TUI or --mode stdout |
| Best when | Scripts, CI, quick runs | Browsing collections, EE images, artifact replay |
Both execute the same playbook tasks—the difference is wrapper features and optional container isolation.
Basic ansible-playbook Syntax
ansible-playbook playbooks/run-demo.ymlCommon options you will use in this guide:
| Option | Short | Purpose |
|---|---|---|
--inventory |
-i |
Inventory path or plugin |
--limit |
Narrow hosts at runtime | |
--syntax-check |
Validate YAML and playbook shape | |
--check |
-C |
Check mode (dry run) |
--diff |
Show file diffs | |
--tags |
Run tagged tasks only | |
--skip-tags |
Skip tagged tasks | |
--start-at-task |
Start execution at a named task | |
--extra-vars |
-e |
Pass runtime variables |
--become |
-b |
Privilege escalation |
--ask-become-pass |
-K |
Prompt for become password |
-v / -vv / -vvv |
Increase verbosity |
Create a small demo playbook for the examples below:
cat > ~/ansible-project/playbooks/run-demo.yml << 'EOF'
---
- name: Run demo
hosts: lab
gather_facts: false
tasks:
- name: Ping hosts
ansible.builtin.ping:
tags: [always]
- name: Ensure demo dir
ansible.builtin.file:
path: /tmp/run-demo
state: directory
mode: "0755"
tags: [config]
- name: Debug skip me
ansible.builtin.debug:
msg: optional task
tags: [optional]
EOFRun a Playbook with Inventory
Use -i when you want to be explicit about which inventory Ansible should use. This is helpful when you have multiple inventories, when you are outside the project directory, or when you are testing a temporary inventory file.
Point at an inventory file explicitly:
ansible-playbook -i inventory/hosts playbooks/run-demo.yml --syntax-checkSample output:
playbook: playbooks/run-demo.yml-i accepts a file, directory, or plugin source. If you skip -i and Ansible cannot find a default inventory, you may get an empty host list or connect to the wrong machines—being explicit avoids that surprise on the first run.
Run a Playbook Using Inventory from ansible.cfg
In a real project, you usually do not want to type -i inventory/hosts every time. Keeping the inventory path in ansible.cfg makes playbook commands shorter and reduces mistakes when the same project is used repeatedly.
Most projects set a default inventory in ansible.cfg so you can omit -i:
ansible-config dump | grep DEFAULT_HOST_LISTSample output:
DEFAULT_HOST_LIST(/home/ansible/ansible-project/ansible.cfg) = ['/home/ansible/ansible-project/inventory/hosts']From the project root, this is enough:
ansible-playbook playbooks/run-demo.ymlAnsible picks up inventory/hosts automatically.
List Target Hosts Before Running
Before a risky run, check which hosts the playbook will target:
ansible-playbook playbooks/run-demo.yml --list-hostsSample output:
playbook: playbooks/run-demo.yml
play #1 (lab): Run demo TAGS: []
pattern: ['lab']
hosts (1):
rocky2This is worth doing before any risky run. It is much easier to catch a wrong host list here than after a playbook has already changed the wrong machine.
Target Hosts with --limit
--limit narrows which inventory hosts run—even if the play lists a broader group:
ansible-playbook playbooks/run-demo.yml --limit rocky2Sample output:
PLAY [Run demo] ****************************************************************
TASK [Ping hosts] **************************************************************
ok: [rocky2]Useful for testing one machine before rolling out to a group. Combine with host patterns from inventory patterns; double-check the limit before production runs.
Check Playbook Syntax Before Running
--syntax-check is the first command to run after editing a playbook. It catches YAML parsing problems and many playbook-structure errors before Ansible connects to managed hosts.
Validate a new or edited playbook without executing tasks:
ansible-playbook playbooks/run-demo.yml --syntax-checkSample output:
playbook: playbooks/run-demo.ymlIf the command prints only the playbook path and exits cleanly, Ansible was able to read the YAML and understand the playbook structure. It does not prove that the playbook logic is correct, that the target package exists, or that every task will succeed. See YAML validation for parse-error examples. When syntax passes but task logic fails, use debug Ansible playbooks to inspect variables and registered output.
Preview Changes with Check Mode
Use check mode when you want to see what Ansible would do without making real changes yet. It is especially helpful before package installs, service restarts, or file updates on shared systems.
Check mode (--check or -C) asks supported modules to report what would change without applying it:
ansible-playbook playbooks/run-demo.yml --checkSample output:
PLAY RECAP *********************************************************************
rocky2 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0If /tmp/run-demo does not exist yet, the file task may report changed in check mode because Ansible predicts that it would create the directory. That predicted change is expected; it does not mean the directory was actually created.
Not every module supports check mode the same way—some fully support it, some partially, and some skip or behave differently. Check mode is a simulation that depends on module support. Always verify important changes on a lab host before trusting --check as a production gate.
Show File Changes with Diff Mode
Use --diff when you need to see the actual file content Ansible would write—not just whether a task reports changed. It is most useful with copy, template, and similar modules.
--diff shows content changes for modules such as copy and template. Create a small copy playbook:
cat > ~/ansible-project/playbooks/diff-demo.yml << 'EOF'
---
- name: Diff demo
hosts: lab
gather_facts: false
tasks:
- name: Deploy motd snippet
ansible.builtin.copy:
dest: /tmp/run-demo/motd.txt
content: "Managed by Ansible\n"
mode: "0644"
EOFPreview the change:
ansible-playbook playbooks/diff-demo.yml --check --diffSample output:
TASK [Deploy motd snippet] *****************************************************
--- before
+++ after: /tmp/run-demo/motd.txt
@@ -0,0 +1 @@
+Managed by Ansible
changed: [rocky2]The --- / +++ block is the preview of what would be written on disk.
Be careful with --diff on files that may contain secrets, because changed content can appear in terminal output or CI logs.
For file-heavy playbooks, keep using both flags together: --check predicts whether a task would change, and --diff shows the file content that would be written. The diff demo above already uses both. After the preview looks correct, run the same playbook again without --check to apply the change.
Increase Output with Verbosity
When a playbook fails and the default output is too short, add -v (up to -vvvv) for more connection and module detail:
ansible-playbook playbooks/run-demo.yml -vSample output:
Using /home/ansible/ansible-project/ansible.cfg as config file
PLAY [Run demo] ****************************************************************
TASK [Ping hosts] **************************************************************
ok: [rocky2] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"}, "changed": false, "ping": "pong"}Start with -v for module JSON; use -vvv or -vvvv when debugging SSH or plugin issues.
Run Selected Tasks with Tags
Tags let you include or exclude parts of a playbook at runtime. Overview only—see Ansible tags for design patterns.
Avoid putting broad tags at play level unless you want every task in that play to inherit them. Ansible inherits tags from plays, blocks, roles, and imports—play-level tags can make --tags run more tasks than you expect.
Use --tags
Run tasks that match a tag. Tasks tagged always still run unless you explicitly skip that tag:
ansible-playbook playbooks/run-demo.yml --tags configSample output:
PLAY RECAP *********************************************************************
rocky2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Here ping (tag always) and Ensure demo dir (tag config) ran—the optional debug task did not.
Use --tags when you want only install, config, or deploy slices—see Ansible tags for how to design tag names.
Use --skip-tags
Skip tasks with a given tag:
ansible-playbook playbooks/run-demo.yml --skip-tags optionalSample output:
PLAY RECAP *********************************************************************
rocky2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0The optional debug task did not run—PLAY RECAP shows two tasks instead of three.
List available tags
ansible-playbook playbooks/run-demo.yml --list-tagsSample output:
playbook: playbooks/run-demo.yml
play #1 (lab): Run demo TAGS: []
TASK TAGS: [always, config, optional]List Tasks Before Running
Use --list-tasks when you want to see which task names Ansible will run without executing them:
ansible-playbook playbooks/run-demo.yml --list-tasksSample output:
playbook: playbooks/run-demo.yml
play #1 (lab): Run demo TAGS: []
tasks:
Ping hosts TAGS: [always]
Ensure demo dir TAGS: [config]
Debug skip me TAGS: [optional]This is useful before combining --tags, --skip-tags, or --limit in larger playbooks.
Use --start-at-task "Task name" only for troubleshooting or resuming a failed run carefully. It skips earlier tasks, so required setup may be missing.
Use Privilege Escalation While Running Playbooks
Many tasks need root on the managed host—installing packages, managing services, or writing files under /etc. You can set become: true in the playbook, in ansible.cfg, or pass it at runtime.
Use -b when the playbook needs root privileges but become: true is not already set in the playbook or ansible.cfg. This is common for package installation, service management, files under /etc, or other root-owned paths.
Use -K only when the remote sudo configuration requires a password. If your automation account has passwordless sudo, -b is usually enough.
Run with privilege escalation:
ansible-playbook playbooks/run-demo.yml -bIf sudo requires a password, combine -b with -K:
ansible-playbook playbooks/run-demo.yml -b -KIf become: true is already set in the playbook or ansible.cfg, you may only need -K to provide the password.
Your ansible.cfg may already set become = True—check before adding -b so you do not wonder why privilege escalation is already active.
Pass Extra Variables at Runtime
Use -e / --extra-vars when you need a one-time override at run time—for example, changing a greeting message, toggling a feature flag, or passing a version number without editing the playbook.
Extra variables have high precedence, so they can override values from inventory, group vars, host vars, and play vars. Use them carefully for one-time runtime changes, not as a replacement for normal variable files.
Override or supply variables with -e:
cat > ~/ansible-project/playbooks/extra-var-demo.yml << 'EOF'
---
- hosts: lab
gather_facts: false
tasks:
- ansible.builtin.debug:
msg: "{{ greeting }}"
EOFansible-playbook playbooks/extra-var-demo.yml -e greeting=from_cliSample output:
ok: [rocky2] => {
"msg": "from_cli"
}Avoid passing secrets on the command line—they appear in shell history and process lists. Use Ansible Vault or a vars file with restrictive permissions for sensitive values.
Run Playbooks with ansible-navigator
ansible-navigator run wraps ansible-playbook with UI and optional execution environments. Configure defaults in ansible-navigator.yml. Many learners edit playbooks in Visual Studio Code with Ansible and run them from the integrated terminal or navigator.
Run in interactive mode
On a local console with a TTY:
ansible-navigator run playbooks/run-demo.ymlOpens the navigator TUI for task-by-task browsing. Over SSH without a terminal, use stdout mode instead.
Run in stdout mode
Plain playbook output for scripts and remote sessions:
ansible-navigator run playbooks/run-demo.yml --mode stdoutSample output:
PLAY [Run demo] ****************************************************************
TASK [Ping hosts] **************************************************************
ok: [rocky2]
PLAY RECAP *********************************************************************
rocky2 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Navigator may add ANSI color codes in your terminal—that is normal for stdout mode.
Run with execution environment enabled
Execution environments are useful when you want the same Ansible version, collections, and Python dependencies everywhere. Instead of relying on whatever is installed on the control node, navigator runs the playbook inside a container image that already contains the required automation content.
With EE enabled (the default in many setups), navigator uses the image defined in ansible-navigator.yml. Choose this when teammates or CI need a predictable toolchain, not when you are doing a quick local test on a small lab VM.
Run with execution environment disabled
When you want navigator's stdout mode or TUI but not a container, disable the execution environment and use the local ansible-core install:
ansible-navigator run playbooks/run-demo.yml --mode stdout --ee falseMatches execution-environment.enabled: false in navigator settings—handy on small lab VMs.
ansible-playbook vs ansible-navigator Output
Both show PLAY, TASK, and PLAY RECAP lines in stdout mode. Differences:
ansible-playbookoutput is the baseline—no TUI, no EE wrapperansible-navigatormay colorize output and can store run artifacts for replay- Interactive navigator adds keyboard navigation—not available in plain
ansible-playbook
For reading normal PLAY, TASK, and PLAY RECAP output, ansible-playbook and ansible-navigator run --mode stdout look similar. Results can still differ if navigator runs inside an execution environment with different collections, Python packages, or configuration.
Quick Command Reference
| Goal | Command |
|---|---|
| Run normally | ansible-playbook playbooks/run-demo.yml |
| Check syntax | ansible-playbook playbooks/run-demo.yml --syntax-check |
| List matched hosts | ansible-playbook playbooks/run-demo.yml --list-hosts |
| Preview changes | ansible-playbook playbooks/run-demo.yml --check |
| Preview file diffs | ansible-playbook playbooks/diff-demo.yml --check --diff |
| Run one host | ansible-playbook playbooks/run-demo.yml --limit rocky2 |
| Run tagged tasks | ansible-playbook playbooks/run-demo.yml --tags config |
| Run with navigator stdout | ansible-navigator run playbooks/run-demo.yml --mode stdout |
Demo playbooks (run-demo.yml, diff-demo.yml, extra-var-demo.yml) are created from the cat blocks earlier in this guide.
Common Playbook Execution Mistakes
| Symptom | Likely cause | Fix |
|---|---|---|
provided hosts list is empty |
Wrong inventory or host pattern | Check -i, ansible.cfg, and play hosts: |
| Changes on wrong server | Typo in --limit |
Run --list-hosts before limiting |
| Check mode output is surprising | Module has partial/no check support, or task is forced with check_mode: false |
Read module docs; test on a lab host before production |
--diff shows nothing |
Task is not file-based | Use copy/template; some modules have no diff |
| Navigator fails on SSH | Interactive mode without TTY | Add --mode stdout |
| Missing collection in navigator | EE image lacks content | Install collection or use --ee false locally |
| Secret leaked | -e password=... on CLI |
Use vault or a protected vars file |
--tags config runs too many tasks |
Tags set at play or role level and inherited by tasks | Move broad tags to specific tasks or review tag inheritance |
Safe Playbook Run Workflow
Treat this as the default habit for a new or changed playbook—not only for production. A practical sequence before touching every host in the inventory:
ansible-playbook play.yml --syntax-check- Confirm inventory:
ansible-playbook play.yml --list-hosts - Preview:
ansible-playbook play.yml --check --diff - Limited run:
ansible-playbook play.yml --limit staging1 - Full run:
ansible-playbook play.yml
Add -v when the first failure needs more context.
Recommended Defaults on the Control Node
cdinto the project root soansible.cfgand inventory resolve- Prefer
--syntax-checkafter every significant playbook edit - Use
--check --diffbefore package, file, or template changes on shared systems - Use
--limitfor the first run on a new play - Use
ansible-navigator run --mode stdoutwhen you want navigator features without the TUI - Keep the hands-on first playbook in playbook examples—this page is the CLI reference
- After your first playbook, learn idempotency before scaling automation
Summary
Run playbooks with ansible-playbook playbooks/site.yml from the project directory, or use ansible-navigator run for stdout or interactive execution. Validate with --syntax-check, preview with --check and --diff, narrow hosts with --limit, and slice work with --tags. Pass runtime data with -e, escalate with -b / -K, and turn up -v when you need deeper logs.
References
- ansible-playbook command — Ansible documentation
- ansible-navigator run — navigator run subcommand
- Tags in Ansible — official tag selection
- Ansible playbook structure — plays, tasks, handlers
- ansible-navigator.yml — navigator settings file
- Ansible tags — tag design and patterns

