Top 60 Ansible Interview Questions (2026)

The 60 Ansible questions interviewers actually ask, with direct answers, runnable playbooks, and what the interviewer is listening for. Grouped for freshers, intermediate, and experienced rounds.

60 questions with answers

What Is Ansible?

Key Takeaways

  • Ansible is an open-source automation tool for configuration management, application deployment, and orchestration, driven by plain YAML.
  • It's agentless: the control node connects to managed hosts over SSH (or WinRM), so there's no daemon to install or maintain on targets.
  • Interviews test idempotency, the module and playbook model, inventory, variables, roles, and how you keep runs safe and repeatable.
  • This page is a question bank: work your tier first, read one tier up, and say answers out loud because delivery gets evaluated too.

Ansible is an open-source IT automation tool that Michael DeHaan created in 2012 and Red Hat now maintains. You describe the state you want in YAML files called playbooks, and Ansible connects to your servers over SSH to make that state real: install packages, edit config files, start services, deploy code. It's agentless, so nothing runs on the managed hosts between jobs, which is a big part of why teams pick it over heavier tools. Runs are idempotent by design: running the same playbook twice leaves the system in the same state, so re-runs are safe. In interviews, Ansible questions probe idempotency, the module system, inventory and variables, roles, and the gotchas that bite in production, not memorized flag lists. This page collects the 60 questions that come up most, each with a direct answer and runnable YAML. If you're building fundamentals, the official Ansible Getting Started guide from Red Hat is the canonical path; increasingly the first technical round is a live AI coding interview, so pair this bank with our AI interview preparation guides for the format side.

60Questions with answers on this page
3Difficulty tiers: freshers, intermediate, experienced
AgentlessAnsible pushes over SSH, no daemon on nodes
YAMLPlaybooks are written in plain YAML

Watch: Ansible for Beginners to Advanced (DevOps Bootcamp)

Video: Ansible for Beginners to Advanced (DevOps Bootcamp) (TechWorld with Nana, YouTube)

Test yourself and earn a certificate

10 quick questions. Score 70%+ to download your Ansible certificate.

Jump to quiz

All Questions on This Page

60 questions
Ansible Interview Questions for Freshers
  1. 1. What is Ansible and what problem does it solve?
  2. 2. What does it mean that Ansible is agentless, and why does that matter?
  3. 3. What is idempotency and why does Ansible care about it?
  4. 4. What is the difference between a playbook, a play, and a task?
  5. 5. What is an inventory and how do you define one?
  6. 6. What is a module in Ansible?
  7. 7. What is an ad-hoc command and when would you use one?
  8. 8. Why does Ansible use YAML, and what YAML gotchas bite beginners?
  9. 9. How do you define and use variables in Ansible?
  10. 10. What is a handler and how does notify work?
  11. 11. What are facts and how does Ansible gather them?
  12. 12. How do you run tasks with elevated privileges?
  13. 13. How do you loop over a list of items in a task?
  14. 14. How do conditionals work with the when keyword?
  15. 15. What does register do?
  16. 16. What are templates and how does Ansible use Jinja2?
  17. 17. What are tags and why use them?
  18. 18. What is the ansible.cfg file for?
  19. 19. What is Ansible Vault and when do you use it?
  20. 20. What is the difference between the command and shell modules?
Ansible Intermediate Interview Questions
  1. 21. What is a role and what is its directory structure?
  2. 22. How does variable precedence work in Ansible?
  3. 23. What is the difference between include and import tasks?
  4. 24. How do blocks and rescue handle errors?
  5. 25. What do changed_when and failed_when do?
  6. 26. What is dynamic inventory and when do you need it?
  7. 27. What are Jinja2 filters and which are commonly used?
  8. 28. What is Ansible Galaxy and how do you use it?
  9. 29. What are collections and why did Ansible move to them?
  10. 30. What does delegate_to do?
  11. 31. How do you do a rolling update with serial?
  12. 32. How do you run long tasks asynchronously?
  13. 33. What is fact caching and why use it?
  14. 34. What does set_fact do, and how does it differ from register?
  15. 35. What is the difference between loop and with_* keywords?
  16. 36. How do you prompt for input at runtime?
  17. 37. What are the special always and never tags?
  18. 38. How do you make a shell or command task idempotent?
  19. 39. What does ignore_errors do and when is it appropriate?
  20. 40. How do you set environment variables for a task?
Ansible Interview Questions for Experienced Engineers
  1. 41. What actually happens when Ansible runs a task on a host?
  2. 42. What are strategy plugins, and how do linear and free differ?
  3. 43. How do you scale Ansible to thousands of hosts?
  4. 44. When and how would you write a custom module?
  5. 45. How do you manage secrets across many environments?
  6. 46. How do you test Ansible roles and playbooks?
  7. 47. What do AWX and Ansible Automation Platform add over the CLI?
  8. 48. How do Ansible and Terraform fit together in a real workflow?
  9. 49. What are connection plugins, and how does Ansible manage Windows?
  10. 50. What are the gotchas with handlers in real playbooks?
  11. 51. A playbook is slow. How do you speed it up?
  12. 52. How do you make a production deploy safe when hosts fail mid-run?
  13. 53. What are lookup plugins and how do they differ from filters?
  14. 54. How would you structure automation for a large organization?
  15. 55. What are the limitations of check mode, and how do you work around them?
  16. 56. What is ansible-pull and when would you use it over push?
  17. 57. A playbook fails only on some production hosts. Walk through your approach.
  18. 58. The real cases where an Ansible playbook is not truly idempotent.
  19. 59. When do you package automation as a role versus a collection?
  20. 60. How does Ansible handle network device automation?

Ansible Interview Questions for Freshers

Freshers20 questions

The fundamentals every entry-level round checks. If any answer here surprises you, that's your study list.

Q1. What is Ansible and what problem does it solve?

Ansible is an open-source automation tool for configuration management, application deployment, and orchestration. You describe the desired state in YAML, and Ansible connects to your servers over SSH to make it happen.

It solves the problem of doing the same setup by hand across many machines. Instead of SSHing into fifty servers to install and configure the same thing, you write one playbook and run it against all of them, repeatably and safely.

Key point: A one-line definition plus the concrete pain it removes (manual, repeated server setup) beats a feature list. Interviewers open with this to hear how you frame a tool.

Watch a deeper explanation

Video: You Need to Learn Ansible RIGHT NOW (Linux Automation) (NetworkChuck, YouTube)

Q2. What does it mean that Ansible is agentless, and why does that matter?

Agentless means you don't install any Ansible software or daemon on the machines you manage. The control node connects to targets over SSH (or WinRM for Windows) using credentials you already have, runs the work, and disconnects.

It matters because there's nothing to install, patch, or keep running on hundreds of hosts, and no extra open port or background process to secure. The requirement is just SSH access and Python on most targets.

Agentless (Ansible)Agent-based (Puppet, Chef)
Software on targetsNone persistentA running agent
ConnectionPush over SSHAgent pulls from a server
Setup costLowHigher
Firewall needsSSH onlyAgent port to the master

Key point: The follow-up is usually 'what does Ansible need on the target then?'. Answer: SSH access and, for most modules, Python.

Watch a deeper explanation

Video: Getting Started with Ansible 01: Introduction (Learn Linux TV, YouTube)

Q3. What is idempotency and why does Ansible care about it?

Idempotency means running the same task again produces the same end state without redoing work. An idempotent task checks the current state first and only acts when something differs, reporting ok instead of changed when the system already matches.

Ansible cares because it lets you run a playbook safely any number of times. You can re-run after a partial failure or on a schedule without worrying that it'll duplicate users, append config twice, or restart services needlessly.

yaml
- name: Ensure nginx is installed
  ansible.builtin.package:
    name: nginx
    state: present
# First run: installs nginx, reports changed
# Second run: already present, reports ok (no change)

Key point: This is the single most probed Ansible idea. Say the definition, then give an example of an idempotent module versus a non-idempotent shell command.

Q4. What is the difference between a playbook, a play, and a task?

A task is a single action, one call to a module, like installing a package. A play maps a set of tasks to a group of hosts. A playbook is a YAML file containing one or more plays, run top to bottom.

So the nesting is playbook contains plays, a play contains tasks, a task calls a module. That hierarchy is worth being able to draw quickly.

yaml
# a playbook (one file)
- name: Configure web servers   # a play
  hosts: webservers
  tasks:
    - name: Install nginx       # a task
      ansible.builtin.package:
        name: nginx
        state: present

Q5. What is an inventory and how do you define one?

Inventory is the list of hosts Ansible manages, usually organized into groups. It can be a static file (INI or YAML) or a dynamic script or plugin that pulls hosts from a cloud provider at runtime.

Groups let a play target a subset of machines, and you can attach variables to hosts or groups. The default file is /etc/ansible/hosts, but most teams keep a project-local inventory and pass it with -i.

ini
[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com

[production:children]
webservers
dbservers

Q6. What is a module in Ansible?

A module is a small program Ansible ships to a managed host to do one job: manage a package, copy a file, create a user, restart a service. Tasks call modules. Ansible has thousands, grouped into collections.

Most modules are idempotent and declarative: you The end state (state: present) and the module figures out whether any change is needed. Modern names are fully qualified, like ansible.builtin.copy.

yaml
- name: Copy a config file
  ansible.builtin.copy:
    src: files/app.conf
    dest: /etc/app/app.conf
    owner: root
    mode: '0644'

Q7. What is an ad-hoc command and when would you use one?

An ad-hoc command runs a single module against hosts straight from the command line, without writing a playbook. You use the ansible command with -m for the module and -a for its arguments.

They're for quick one-offs: check uptime, restart a service, ping all hosts to confirm reachability. For anything you'll repeat or want in version control, write a playbook instead.

bash
# ping all hosts
ansible all -m ping

# check disk usage on webservers
ansible webservers -m ansible.builtin.command -a 'df -h'

# restart nginx, with sudo
ansible webservers -m ansible.builtin.service -a 'name=nginx state=restarted' --become

Watch a deeper explanation

Video: Getting Started with Ansible 05: Running Elevated Ad-Hoc Commands (Learn Linux TV, YouTube)

Q8. Why does Ansible use YAML, and what YAML gotchas bite beginners?

Ansible uses YAML because it's readable without knowing a programming language: indentation shows structure, and lists and key-value pairs map cleanly to plays and tasks. Non-programmers can read a playbook and follow it.

The classic gotchas: tabs are illegal (spaces only), indentation must be consistent, and values like yes, no, on, off get read as booleans unless quoted. A colon inside an unquoted string also breaks parsing.

Key point: the boolean and quoting traps matters.

Q9. How do you define and use variables in Ansible?

Variables can be set in the playbook (vars), in separate vars files, in inventory (host and group vars), passed on the command line with -e, or registered from a task's output. You reference them with Jinja2: {{ my_var }}.

Group and host variables usually live in group_vars/ and host_vars/ directories, which keeps environment-specific values out of the playbook itself.

yaml
- hosts: webservers
  vars:
    app_port: 8080
  tasks:
    - name: Show the port
      ansible.builtin.debug:
        msg: "App runs on port {{ app_port }}"

Q10. What is a handler and how does notify work?

A handler is a task that runs only when another task notifies it, and only if that task actually changed something. Handlers run once, at the end of the play, no matter how many tasks notified them.

The classic use is restarting a service after its config changed. If the config file didn't change, the task reports ok, the handler isn't notified, and the service isn't restarted needlessly.

yaml
tasks:
  - name: Deploy nginx config
    ansible.builtin.template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: Restart nginx

handlers:
  - name: Restart nginx
    ansible.builtin.service:
      name: nginx
      state: restarted

Key point: The expected depth point: handlers run at the end and only on change. Volunteer that and you've answered the follow-up.

Q11. What are facts and how does Ansible gather them?

Facts are pieces of system information Ansible collects from each host before running tasks: OS family, IP addresses, memory, disk, and more. They're exposed as variables under ansible_facts.

Gathering happens automatically via the setup module at the start of a play. You can turn it off with gather_facts: false to speed things up when you don't need them.

yaml
- hosts: all
  tasks:
    - name: Show the OS family
      ansible.builtin.debug:
        msg: "{{ ansible_facts['os_family'] }}"

Q12. How do you run tasks with elevated privileges?

Use become: true to run a task or play as another user, root by default, through a privilege tool like sudo. become_user sets the target user and become_method sets the mechanism.

You can set it at the play level for everything or on a single task that needs root. The connecting SSH user still needs permission to escalate.

yaml
- hosts: webservers
  become: true
  tasks:
    - name: Install a package (needs root)
      ansible.builtin.package:
        name: htop
        state: present

Q13. How do you loop over a list of items in a task?

Use the loop keyword and reference each element with the item variable. It replaces writing the same task many times, so you can create several users or install several packages in one task.

Older playbooks use with_items, which still works but loop is the current recommendation for simple lists.

yaml
- name: Create several users
  ansible.builtin.user:
    name: "{{ item }}"
    state: present
  loop:
    - alice
    - bob
    - carol

Q14. How do conditionals work with the when keyword?

when runs a task only if a Jinja2 expression is true. You reference facts or variables directly (no curly braces needed inside when), so you can branch on the OS, on a registered result, or on any variable.

Common uses: run apt only on Debian family and yum only on Red Hat family, or skip a step unless a previous task changed something.

yaml
- name: Install nginx on Debian family only
  ansible.builtin.apt:
    name: nginx
    state: present
  when: ansible_facts['os_family'] == 'Debian'

Watch a deeper explanation

Video: Getting Started with Ansible 07: The when Conditional (Learn Linux TV, YouTube)

Q15. What does register do?

register captures a task's output into a variable so later tasks can use it. The registered value holds fields like stdout, rc (return code), and changed, depending on the module.

It's how you make one task's result drive the next: run a command, register the result, then act on it with when or debug.

yaml
- name: Check if a file exists
  ansible.builtin.stat:
    path: /etc/app/config
  register: cfg

- name: Warn if missing
  ansible.builtin.debug:
    msg: "Config is missing"
  when: not cfg.stat.exists

Q16. What are templates and how does Ansible use Jinja2?

A template is a file with Jinja2 placeholders that Ansible fills with variables and facts, then copies to the host. The template module renders a .j2 file per host, so each machine gets a config with its own values.

Templates cover config files that differ by host: a port here, a hostname there, a loop over a list of upstreams. Jinja2 gives you variables, conditionals, loops, and filters inside those files.

yaml
- name: Render the app config
  ansible.builtin.template:
    src: templates/app.conf.j2
    dest: /etc/app/app.conf
# app.conf.j2 contains: listen {{ app_port }};

Q17. What are tags and why use them?

Tags label tasks, roles, or plays so you can run or skip parts of a playbook. You run only tagged tasks with --tags and exclude them with --skip-tags.

They save time on long playbooks: re-run just the config step or just the deploy step without executing everything. Overusing tags can make a playbook hard to follow, so keep them meaningful.

yaml
- name: Deploy application code
  ansible.builtin.git:
    repo: https://example.com/app.git
    dest: /opt/app
  tags:
    - deploy
# run only this: ansible-playbook site.yml --tags deploy

Q18. What is the ansible.cfg file for?

ansible.cfg holds configuration defaults: the inventory path, remote user, privilege settings, SSH options, and where roles and collections live. It saves passing the same flags every run.

Ansible searches for it in a set order: the ANSIBLE_CONFIG env var, then the current directory, then the user's home, then /etc/ansible. A project-local ansible.cfg is the usual pattern.

Q19. What is Ansible Vault and when do you use it?

Ansible Vault encrypts sensitive data (passwords, API keys, certificates) so it can live in version control safely. You can encrypt a whole file or single values, and Ansible decrypts them at runtime with a password or key.

You edit encrypted files with ansible-vault edit and supply the password at run time with --ask-vault-pass or a vault password file.

bash
# encrypt a secrets file
ansible-vault encrypt group_vars/prod/secrets.yml

# run a playbook that uses it
ansible-playbook site.yml --ask-vault-pass

Q20. What is the difference between the command and shell modules?

command runs a program directly without a shell, so pipes, redirects, and environment variable expansion don't work. shell runs the command through /bin/sh, so those features do work.

Prefer command when you can, because it's safer (no shell injection surface). Reach for shell only when you genuinely need shell features. And prefer a purpose-built module over either, since command and shell aren't idempotent.

Key point: The senior-sounding close: 'both are a last resort because they aren't idempotent, so I use changed_when or a real module instead.'

Back to question list

Ansible Intermediate Interview Questions

Intermediate20 questions

For candidates with working experience: playbook design, variable precedence, roles, and the questions that separate users from understanders.

Q21. What is a role and what is its directory structure?

A role is a reusable package of automation: tasks, handlers, variables, defaults, templates, and files organized in a standard directory layout. You include a role in a play and it drops in a whole chunk of proven behavior.

The layout uses fixed subdirectories, each with a main.yml Ansible loads automatically. This convention is why roles are shareable, testable, and publishable to Ansible Galaxy.

text
roles/
  webserver/
    tasks/main.yml
    handlers/main.yml
    templates/
    files/
    vars/main.yml
    defaults/main.yml
    meta/main.yml

Key point: Knowing which directory holds what (defaults are lowest precedence, vars are higher) is the follow-up. Have that ready.

Watch a deeper explanation

Video: Getting Started with Ansible 06: Writing Our First Playbook (Learn Linux TV, YouTube)

Q22. How does variable precedence work in Ansible?

When the same variable is set in multiple places, Ansible follows a defined precedence order and the highest wins. Roughly, from lowest to highest: role defaults, inventory vars, playbook vars, host and group vars, facts, and extra vars (-e), which beats everything.

The two anchors worth memorizing: role defaults are the weakest (they're meant to be overridden) and extra vars on the command line are the strongest. Everything else falls between.

SourcePrecedence
role defaultsLowest
inventory group_vars / host_varsLow to middle
play vars / vars_filesMiddle
role vars (vars/main.yml)High
extra vars (-e)Highest, wins everything

Key point: Nobody memorizes all 22 tiers. Naming the two extremes correctly (defaults weakest, -e strongest) is what the question actually checks.

Q23. What is the difference between include and import tasks?

import is static: Ansible processes it when it parses the playbook, before the run. include (include_tasks) is dynamic: it's resolved during execution, when the task is reached.

The practical consequences: imports let tags and handlers apply to the imported tasks up front, but you can't loop over an import or use a runtime variable in its filename. Includes can loop and use runtime values, but tags behave differently. Choose static unless you need runtime behavior.

import_tasksinclude_tasks
When resolvedParse time (static)Run time (dynamic)
Can loop over itNoYes
Runtime var in filenameNoYes
Tags apply to inner tasksYes, directlyOnly via apply/rules

Q24. How do blocks and rescue handle errors?

A block groups tasks. Pair it with rescue (runs if any task in the block fails) and always (runs no matter what) to get try/catch/finally style error handling in a playbook.

This lets you attempt something risky, recover or clean up on failure, and guarantee a final step. Blocks also let you apply when, become, or tags to a group of tasks at once.

yaml
- block:
    - name: Try a deployment
      ansible.builtin.command: /opt/deploy.sh
  rescue:
    - name: Roll back on failure
      ansible.builtin.command: /opt/rollback.sh
  always:
    - name: Always notify
      ansible.builtin.debug:
        msg: "Deploy step finished"

Q25. What do changed_when and failed_when do?

They override how Ansible decides a task's status. changed_when tells Ansible when to report changed (useful for command/shell, which always report changed by default). failed_when defines a custom failure condition.

These are how you make otherwise non-idempotent commands behave: run a check, register the result, and set changed_when: false so the task reports ok when nothing actually changed.

yaml
- name: Check app health
  ansible.builtin.command: /opt/app/health
  register: health
  changed_when: false
  failed_when: health.rc != 0 and 'starting' not in health.stdout

Q26. What is dynamic inventory and when do you need it?

Dynamic inventory generates the host list at runtime from an external source instead of a static file. Inventory plugins query AWS, Azure, GCP, or a CMDB and return current hosts, grouped by tags or attributes.

You need it whenever hosts change often: autoscaling groups, cloud instances that come and go, or any environment where maintaining a static file by hand would drift out of date immediately.

yaml
# aws_ec2.yml inventory plugin config
plugin: amazon.aws.aws_ec2
regions:
  - us-east-1
keyed_groups:
  - key: tags.Role
    prefix: role

Q27. What are Jinja2 filters and which are commonly used?

Filters transform a value inside a template or expression, written with a pipe: {{ name | upper }}. Ansible ships many for defaults, type conversion, lists, and formatting.

Everyday ones: default (supply a fallback), to_json / to_yaml, join, map, select and reject (filter lists), and length. default is the one that prevents undefined-variable errors.

yaml
- name: Use a fallback if a var is unset
  ansible.builtin.debug:
    msg: "Port is {{ app_port | default(8080) }}"

- name: Join a list
  ansible.builtin.debug:
    msg: "{{ ['a', 'b', 'c'] | join(', ') }}"

Q28. What is Ansible Galaxy and how do you use it?

Galaxy is the public hub for sharing roles and collections. ansible-galaxy install pulls a role, and ansible-galaxy collection install pulls a collection, so you reuse community automation instead of rewriting it.

A requirements.yml file pins the roles and collections a project needs, which makes environments reproducible. ansible-galaxy init also scaffolds a new role's directory structure for you.

bash
# install roles and collections from requirements.yml
ansible-galaxy install -r requirements.yml
ansible-galaxy collection install -r requirements.yml

Q29. What are collections and why did Ansible move to them?

A collection is a distributable bundle of modules, roles, plugins, and playbooks under a namespace, like community.general or amazon.aws. Since Ansible 2.10, most content lives in collections rather than the core install.

The move split the huge monolith into ansible-core plus separately versioned collections, so content ships and updates on its own schedule. That's why you use fully qualified names like ansible.builtin.copy now.

Q30. What does delegate_to do?

delegate_to runs a specific task on a different host than the one the play is currently targeting, while keeping that host's variables and context. The play loops over web servers, but one task runs somewhere else.

The classic uses: add or remove a host from a load balancer (run the LB task on the LB), or update DNS or monitoring from a control host during a rolling deploy.

yaml
- name: Take server out of the load balancer
  ansible.builtin.command: /usr/bin/lb-remove {{ inventory_hostname }}
  delegate_to: loadbalancer.example.com

Q31. How do you do a rolling update with serial?

serial limits how many hosts a play runs on at once. Instead of hitting all web servers simultaneously, serial: 2 updates two, then the next two, so the service stays available during a deploy.

You can pass a number, a percentage, or a list to ramp up (1, then 5, then the rest). Combine it with health checks and load balancer delegation for a safe rolling deployment.

yaml
- hosts: webservers
  serial: 2          # two at a time
  max_fail_percentage: 25
  tasks:
    - name: Deploy new release
      ansible.builtin.command: /opt/deploy.sh

Q32. How do you run long tasks asynchronously?

async sets a maximum runtime and poll sets how often Ansible checks in. With poll greater than zero, Ansible waits but avoids SSH timeouts on slow tasks. With poll: 0, it fires the task and moves on (fire and forget).

For fire-and-forget work, register the job and check it later with the async_status module. This suits long-running installs or jobs that outlive the SSH connection.

yaml
- name: Run a long job without blocking
  ansible.builtin.command: /opt/long-import.sh
  async: 3600
  poll: 0
  register: long_job

Q33. What is fact caching and why use it?

Fact caching stores gathered facts (in Redis, a JSON file, or memory) so later runs can reuse them instead of gathering from scratch. You configure a caching plugin in ansible.cfg.

It speeds up playbooks against large inventories and lets one host reference another host's facts even when that host isn't in the current play. The trade-off is staleness, so set a sensible timeout.

Q34. What does set_fact do, and how does it differ from register?

set_fact creates or updates a variable during a run from any expression you build. register captures a task's raw output. You often register a result, then set_fact to extract or compute the piece you actually want.

set_fact values persist for the rest of the play on that host and, unlike vars, they're evaluated at that moment, so they're the tool for values computed mid-run.

yaml
- name: Compute a derived value
  ansible.builtin.set_fact:
    backup_name: "app-{{ ansible_date_time.date }}.tar.gz"

- ansible.builtin.debug:
    var: backup_name

Q35. What is the difference between loop and with_* keywords?

loop is the current, recommended way to iterate over a simple list. The older with_items, with_dict, with_nested, and similar keywords use lookup plugins and still work, but loop plus filters covers most of them more clearly.

For complex iteration (nested lists, dict items, indexed loops), you combine loop with filters like dict2items or the subelements lookup rather than a dedicated with_ keyword.

yaml
# modern: loop over dict items
- name: Create users with shells
  ansible.builtin.user:
    name: "{{ item.key }}"
    shell: "{{ item.value }}"
  loop: "{{ user_shells | dict2items }}"

Q36. How do you prompt for input at runtime?

vars_prompt asks the user for a value when the playbook starts, before any task runs. You can mark a prompt private so the input is hidden, which suits passwords.

Use it sparingly: interactive prompts block automation and CI. For secrets in automated runs, Vault or a secret manager fits better; prompts are for occasional manual playbooks.

yaml
- hosts: all
  vars_prompt:
    - name: db_password
      prompt: "Enter the database password"
      private: true
  tasks:
    - ansible.builtin.debug:
        msg: "Received {{ db_password | length }} characters"

Q37. What are the special always and never tags?

A task tagged always runs on every play run unless you explicitly skip it with --skip-tags always. A task tagged never runs only when you request it by name with --tags.

always suits setup steps that must not be skipped; never suits expensive or dangerous tasks you want available but off by default, like a full rebuild.

Q38. How do you make a shell or command task idempotent?

By default command and shell always report changed and always run, so they break idempotency. You fix this three ways: use creates or removes so the task skips if a file already exists, set changed_when based on the output, or replace it with a real module.

The best fix is usually a purpose-built module. When you must shell out, creates is the cleanest guard, and changed_when: false stops it from lying about changes.

yaml
- name: Extract only if not already done
  ansible.builtin.command: tar xzf /tmp/app.tar.gz -C /opt/app
  args:
    creates: /opt/app/VERSION   # skips if this exists

Key point: This question is really 'do you understand idempotency deeply?'. Naming creates plus changed_when plus 'prefer a module' is the full-marks answer.

Q39. What does ignore_errors do and when is it appropriate?

ignore_errors: true lets a play continue even if a task fails, instead of stopping the host. The task still reports failed, but execution moves on.

Use it sparingly, mainly with a following task that checks the registered result and reacts. Blanket ignore_errors hides real problems; a block with rescue is usually the cleaner way to handle expected failures.

Q40. How do you set environment variables for a task?

The environment keyword injects variables into a task's or play's execution environment, which suits commands that read things like PATH, http_proxy, or a tool's config location.

It applies to the task it's attached to (or the whole play if set there) and doesn't persist on the host beyond the run.

yaml
- name: Run a build behind a proxy
  ansible.builtin.command: make build
  environment:
    http_proxy: http://proxy.example.com:8080
    PATH: "/opt/tools/bin:{{ ansible_env.PATH }}"
Back to question list

Ansible Interview Questions for Experienced Engineers

Experienced20 questions

advanced rounds probe design judgment, scale, security, and production scars. Expect every answer here to draw a follow-up.

Q41. What actually happens when Ansible runs a task on a host?

For each task, Ansible takes the module code, combines it with the arguments, and transfers a self-contained package to the target over SSH. The host runs it (usually with Python), returns JSON, and Ansible cleans up. Nothing persists.

Senior-level extras: modules run one host at a time up to the fork count, connection pipelining reduces round trips, and the strategy plugin (linear by default, free as an alternative) controls how hosts progress through the play.

Key point: pipelining and the fork count matters.

Q42. What are strategy plugins, and how do linear and free differ?

A strategy plugin decides how hosts move through a play's tasks. The default, linear, runs each task on all hosts before moving to the next, so hosts stay in lockstep. free lets each host race ahead through tasks as fast as it can.

linear makes ordering predictable and handlers cleaner across hosts. free finishes faster when hosts vary in speed but sacrifices that lockstep. There's also host_pinned for keeping a host on one worker.

StrategyBehaviorBest for
linear (default)All hosts finish a task before the nextPredictable ordering, most plays
freeEach host races ahead independentlyUneven host speeds, faster overall
host_pinnedA host sticks to one workerStateful or connection-heavy work

Q43. How do you scale Ansible to thousands of hosts?

Raise forks to run more hosts in parallel, enable SSH pipelining and ControlPersist to cut connection overhead, use fact caching to skip repeated gathering, and lean on dynamic inventory so the host list stays accurate. For very large fleets, split into batches with serial.

Beyond one control node, teams add AWX or Ansible Automation Platform for a job queue, distributed execution, RBAC, and scheduling. The honest coverage names both the tuning knobs and the point where a controller pays off.

Q44. When and how would you write a custom module?

Write one when no existing module fits and you'd otherwise abuse command or shell in a non-idempotent way. A module is usually a Python script that reads JSON arguments, does its work, and returns JSON with changed and any results.

The AnsibleModule helper handles argument parsing, check mode, and the output format. Before writing one, check whether a collection already covers it, since the ecosystem is large.

python
from ansible.module_utils.basic import AnsibleModule

def main():
    module = AnsibleModule(argument_spec=dict(
        name=dict(type='str', required=True),
    ))
    # ... do work, decide if anything changed ...
    module.exit_json(changed=True, name=module.params['name'])

if __name__ == '__main__':
    main()

Q45. How do you manage secrets across many environments?

Vault encrypts secrets at rest in the repo, and you separate secrets per environment with vault IDs so prod and staging use different keys. For dynamic or centrally rotated secrets, pull them at runtime from a secret manager (HashiCorp Vault, AWS Secrets Manager) via lookup plugins rather than storing them at all.

The mature setup mixes both: Ansible Vault for static config secrets in git, an external manager for high-value or rotating credentials, and vault passwords supplied by a script, never committed.

Q46. How do you test Ansible roles and playbooks?

Molecule is the standard: it spins up a container or VM, applies the role, and runs verifications, including an idempotence check that fails if a second run reports changes. Add ansible-lint for style and correctness, and yamllint for the YAML itself.

A strong pipeline runs lint, then molecule converge and idempotence, then verify assertions, in CI on every change. The idempotence test is the one that catches the most real bugs.

bash
# typical CI sequence
ansible-lint
molecule test   # create, converge, idempotence, verify, destroy

Key point: Naming molecule's idempotence step specifically signals you've tested roles properly, not just run them once and shipped.

Q47. What do AWX and Ansible Automation Platform add over the CLI?

They wrap Ansible in a web UI and API: a job queue, scheduled runs, role-based access control, encrypted credential storage, a visual inventory, and workflows that chain playbooks. AWX is the open-source upstream; Automation Platform is the supported Red Hat product.

The value is operational, not new automation power. Teams adopt it when many people need to run playbooks safely, with audit logs, approvals, and secrets that operators never see in plaintext.

Q48. How do Ansible and Terraform fit together in a real workflow?

Terraform provisions infrastructure (VMs, networks, load balancers) and tracks it in state. Ansible configures what's inside those machines after they exist: packages, users, services, app code. They're sequential, not competing.

A common pipeline: Terraform creates the servers and outputs their addresses, then Ansible reads that inventory (often dynamic) and configures them. Using each for its strength, provisioning versus configuration, is the answer the question needs.

TerraformAnsible
Primary jobProvision infrastructureConfigure machines
State trackingYes, a state fileNo, checks live state each run
LanguageHCLYAML
Typical orderFirstSecond

Q49. What are connection plugins, and how does Ansible manage Windows?

A connection plugin defines how Ansible reaches a host. ssh is the default for Linux; winrm connects to Windows; local runs on the control node; and there are plugins for containers (docker) and network devices.

For Windows, you set ansible_connection: winrm, use the windows and ansible.windows collections, and PowerShell-based modules replace the Python ones. Networking gear often uses network_cli with vendor collections and no Python on the device.

Q50. What are the gotchas with handlers in real playbooks?

Handlers run at the end of the play, so if the play fails before reaching them, notified handlers don't run and the change (like a config edit without a restart) is left half-applied. force_handlers or meta: flush_handlers addresses this.

Other traps: a handler runs once even if notified many times, handlers are matched by name so duplicates collide, and flush_handlers lets you force them mid-play when order matters. These details separate real experience from tutorial knowledge.

yaml
tasks:
  - name: Update config
    ansible.builtin.template:
      src: app.conf.j2
      dest: /etc/app.conf
    notify: Restart app

  - name: Force handlers to run now
    ansible.builtin.meta: flush_handlers

Q51. A playbook is slow. How do you speed it up?

Measure first with profiling callbacks (the profile_tasks callback shows per-task time). Then attack the biggest costs: raise forks for more parallelism, enable SSH pipelining, cache facts or disable gathering where not needed, and cut needless loops and command tasks.

Structural wins matter too: fewer round trips per host (pipelining), async for long jobs, and batching hosts. the check is that you profile before guessing, then fix in impact order.

ini
# ansible.cfg
[defaults]
forks = 50
callbacks_enabled = profile_tasks

[ssh_connection]
pipelining = True

Q52. How do you make a production deploy safe when hosts fail mid-run?

Combine serial for rolling batches, max_fail_percentage to abort if too many hosts fail, health checks between batches, and block/rescue to roll back a failed host cleanly. Delegate load balancer removal and re-add around each batch so users never hit a broken node.

The mindset to convey: assume a host will fail, and design so one failure stops the rollout early instead of taking down the fleet. any_errors_fatal is the harshest version, halting on the first failure.

yaml
- hosts: webservers
  serial: "25%"
  max_fail_percentage: 10
  any_errors_fatal: false
  tasks:
    - name: Deploy release
      ansible.builtin.command: /opt/deploy.sh

What one rolling batch looks like

1Remove from load balancer
delegate_to the LB so users stop hitting these hosts
2Deploy the new release
run the update on this batch only, thanks to serial
3Health check
confirm the batch is healthy before it takes traffic again
4Re-add and check the fail budget
put hosts back, and abort if max_fail_percentage is breached

max_fail_percentage stops the rollout early instead of breaking every host.

Q53. What are lookup plugins and how do they differ from filters?

Lookups fetch data from outside the playbook during templating: read a file, query a secret manager, pull an environment variable, or generate a password. You call them with the lookup function or the query form.

The difference from filters: a filter transforms a value you already have; a lookup goes and gets a value from an external source. Lookups run on the control node, which matters for security and for where files must exist.

yaml
- name: Read a secret from the environment
  ansible.builtin.debug:
    msg: "{{ lookup('env', 'DB_PASSWORD') }}"

- name: Pull each line of a file
  ansible.builtin.debug:
    msg: "{{ item }}"
  loop: "{{ query('lines', 'cat /etc/hosts') }}"

Q54. How would you structure automation for a large organization?

Split shared, reusable content into internal collections and roles with pinned versions in requirements.yml, keep environment data in per-environment inventory with group_vars, and separate secrets into Vault or an external manager. Playbooks stay thin, orchestrating roles rather than holding logic.

Add CI that lints and molecule-tests every role, a controller (AWX or Automation Platform) for RBAC and audited runs, and clear naming conventions. The theme is the same as any codebase: reuse, versioning, testing, and least privilege.

Q55. What are the limitations of check mode, and how do you work around them?

Check mode can't run everything accurately: tasks that depend on a change made earlier in the play (a package that a later task configures) may report wrong because the earlier change didn't actually happen. Some modules don't support check mode at all.

Workarounds: mark read-only tasks with check_mode: false so they run even in a dry run, use --diff to see real file changes, and accept that check mode is a strong preview, not a perfect simulation. Saying that boundary out loud is the production signal.

Q56. What is ansible-pull and when would you use it over push?

ansible-pull inverts the model: each host runs Ansible on itself, pulling playbooks from a git repo and applying them locally, usually on a cron or systemd timer. It's pull-based, like Puppet or Chef.

Use it when you have many nodes that should self-configure without a central push, or nodes that aren't always reachable from a control node (edge devices, autoscaling instances that configure themselves at boot). The trade-off is less central control and no single run view without extra tooling.

bash
# each host pulls and applies its own config
ansible-pull -U https://git.example.com/infra.git local.yml

Q57. A playbook fails only on some production hosts. Walk through your approach.

Narrow scope first: run against one failing host with --limit and bump verbosity to -vvv to see the module and connection detail. Compare a failing host's facts and group_vars against a passing one, since precedence or a missing variable is a common cause.

Then reproduce safely with --check --diff or --start-at-task to jump to the failing step, register and debug the offending task's output, and correlate with recent inventory or role changes. The structure, observe, isolate, compare, verify, is what matters.

Key point: The methodology is; --limit and -vvv are supporting evidence.

Q58. The real cases where an Ansible playbook is not truly idempotent.

command and shell without creates/changed_when, the lineinfile module when a regex matches loosely and edits the wrong line, template output that includes a timestamp so it always differs, and any module used with a force option that overwrites unconditionally.

The senior point: idempotency is a property you have to protect, not a guarantee. You verify it by running twice and confirming the second run reports zero changes, which is exactly what molecule's idempotence test automates.

Key point: Giving concrete non-idempotent examples (not just the definition) is what separates someone who's debugged this from someone who's read about it.

Q59. When do you package automation as a role versus a collection?

A role packages a set of tasks and their assets for one job: configure nginx, set up a user. A collection is broader: it can hold many roles plus custom modules, plugins, and playbooks under a namespace, versioned and distributable as a unit.

Reach for a role when you're bundling tasks for reuse inside your projects. Reach for a collection when you're shipping modules or plugins, or distributing a whole toolkit across teams or publicly, since only collections carry plugin code cleanly.

Q60. How does Ansible handle network device automation?

Network modules run on the control node and talk to devices over their management API or CLI (network_cli, netconf, httpapi connection plugins), because switches and routers usually can't run Python locally. Vendor collections (cisco.ios, arista.eos, junipernetworks.junos) provide the modules.

The patterns differ from server config: you push configuration lines or structured intent, gather device facts, and often render config from templates. Idempotency comes from the module comparing running config to desired, not from a package manager.

Back to question list

Ansible vs Puppet, Chef, and Terraform

Ansible wins when you want low setup cost and a gentle on-ramp: agentless push over SSH, YAML instead of a custom language, and one binary on the control node. It trades some scale ergonomics for that simplicity, so very large fleets sometimes reach for a pull-based agent model. Puppet and Chef are agent-based and use a declarative DSL or Ruby, which suits big managed estates but costs more to stand up. Terraform is a different job entirely: it provisions cloud infrastructure and tracks state, where Ansible configures machines after they exist. Teams often run Terraform then Ansible, not one instead of the other. Saying these boundaries out loud is itself an interview signal.

ToolModelLanguageBest at
AnsibleAgentless push (SSH)YAMLConfig management, app deploy, quick start
PuppetAgent, pullPuppet DSLLarge managed fleets, enforced state
ChefAgent, pullRuby DSLProgrammable config, developer-heavy shops
TerraformAgentless, state fileHCLProvisioning cloud infrastructure
SaltStackAgent or agentlessYAML + PythonEvent-driven automation at scale

How to Prepare for a Ansible Interview

Prepare in layers, and practice out loud. Most Ansible rounds move from concept questions to reading or writing a playbook to a scenario or debugging discussion, so rehearse each stage rather than only reading answers.

  • Master your tier's concepts until you can explain them without notes, then read one tier up for the stretch questions.
  • Write and run real playbooks against a couple of throwaway VMs or containers; running beats reading for cementing idempotency.
  • Practice reading a playbook aloud and predicting what changes on the first run versus the second (idempotency is the favorite probe).
  • Take the quiz on this page to find weak spots, then revisit those questions before the real round.

The typical Ansible interview flow

1Recruiter or phone screen
background, tools used, a few concept checks
2Technical concepts
idempotency, modules, inventory, variables, roles
3Playbook exercise
read, fix, or write a playbook and explain it
4Scenario or debugging
trade-offs, a failing run, secrets, real-world follow-ups

Earlier rounds increasingly run as AI coding interviews. The concepts on this page are what gets probed at every stage.

Test Yourself: Ansible Quiz

Ready to test your Ansible knowledge?

10 questions, about 6 minutes. Score 70% or higher to earn a shareable certificate.

10 questions Instant feedback Free certificate on 70%+

Frequently  Asked  Questions

Which Ansible topics should I prioritize before a technical round?

Prioritize the areas that change real decisions: fundamentals, practical tasks, debugging, trade-offs, and evidence. The highest-value questions are tied to a project example, a validation check, or a failure mode.

Are these questions enough to pass an Ansible interview?

They cover the question-answer portion well, but most Ansible rounds also include a playbook exercise: reading, fixing, or writing YAML while explaining your thinking. running real playbooks against a throwaway VM is the practice path. Our AI coding interview prep guide covers that format, including how automated evaluation reads your process.

Which Ansible version do these answers assume?

Modern Ansible, meaning the ansible-core plus collections model introduced around 2.10 and current today. Fully qualified collection names like ansible.builtin.copy are the norm now. If an interviewer works on an older 2.9-era codebase, the concepts carry over; only the module paths and packaging differ.

Do I need to know Python to use Ansible?

No for day-to-day use: playbooks are YAML and cover most work. Python helps when you write custom modules, filter plugins, or dynamic inventory scripts, and Ansible itself runs on Python on the control node. For most interviews, strong YAML and Jinja2 templating matter more than deep Python.

How long does it take to prepare for an Ansible interview?

If you already write playbooks at work, one to two weeks of an hour a day covers this bank with practice runs. Starting colder, plan three to four weeks and run playbooks daily against test hosts; reading answers without running anything is how preparation quietly fails.

Is there a way to test my Ansible knowledge?

Yes. The quiz on this page scores you as you go and explains every answer, so you find your weak spots fast. Pass the threshold and you can download a shareable certificate with your name and score, free and with no sign-up. It's the quickest way to check yourself before the real round.

From the team that builds coding interviews

Hyring builds the AI Coding Interviewer that runs live technical rounds in 20+ languages for 5,000+ hiring teams. These Ansible questions and scoring notes reflect what actually gets asked and evaluated inside the interviews we host.

See how the AI Coding Interviewer works

Sources

Adithyan RKWritten by Adithyan RK
Surya N
Fact-checked by Surya N
Published on: 28 Apr 2026Last updated: 19 Jun 2026
Share: