Ansible playbook_dir — Magic Variable for Relative Paths
Introduction
playbook_dir is an Ansible magic variable that contains the absolute path to the directory where the currently running playbook is located. It's essential for building portable automation that references files, templates, and includes using paths relative to the playbook — regardless of where ansible-playbook is executed from.
Quick Reference
- name: Show playbook directory
ansible.builtin.debug:
msg: "Playbook is at: {{ playbook_dir }}"
# Output: "Playbook is at: /home/user/ansible/playbooks"
How It Works
project/
├── playbooks/
│ ├── deploy.yml ← playbook_dir = /full/path/to/project/playbooks
│ └── maintenance.yml
├── files/
│ └── config.ini
├── templates/
│ └── app.conf.j2
└── inventory/
└── hosts.yml
# Regardless of where you run from:
cd /tmp
ansible-playbook /home/user/project/playbooks/deploy.yml
# playbook_dir = /home/user/project/playbooks
Common Use Cases
Reference Files Relative to Playbook
- name: Copy file using playbook-relative path
ansible.builtin.copy:
src: "{{ playbook_dir }}/../files/config.ini"
dest: /etc/myapp/config.ini
- name: Include vars from parent directory
ansible.builtin.include_vars:
file: "{{ playbook_dir }}/../vars/secrets.yml"
Load Templates from Custom Location
- name: Deploy template from shared directory
ansible.builtin.template:
src: "{{ playbook_dir }}/../templates/nginx.conf.j2"
dest: /etc/nginx/nginx.conf
Dynamic Includes
- name: Include environment-specific tasks
ansible.builtin.include_tasks:
file: "{{ playbook_dir }}/tasks/{{ env }}.yml"
- name: Include playbook-local role
ansible.builtin.include_role:
name: "{{ playbook_dir }}/../roles/common"
Build Paths for Scripts
- name: Run local script
ansible.builtin.script:
cmd: "{{ playbook_dir }}/../scripts/setup.sh"
- name: Read local file
ansible.builtin.set_fact:
config_content: "{{ lookup('file', playbook_dir + '/../config/defaults.json') }}"
playbook_dir vs Other Path Variables
| Variable | Value | Use When |
|---|---|---|
playbook_dir | Directory of the playbook | Referencing files relative to playbook |
role_path | Directory of the current role | Inside roles, for role-local files |
inventory_dir | Directory of the inventory file | Referencing inventory-relative files |
ansible_config_file | Path to ansible.cfg | Rarely needed directly |
# Inside a role:
- name: In a role, use role_path
ansible.builtin.copy:
src: "{{ role_path }}/files/cert.pem" # Preferred inside roles
dest: /etc/ssl/cert.pem
# In a playbook:
- name: In a playbook, use playbook_dir
ansible.builtin.copy:
src: "{{ playbook_dir }}/files/cert.pem" # Preferred in playbooks
dest: /etc/ssl/cert.pem
With import_playbook and include_playbook
# main.yml (playbook_dir = /project/playbooks)
- ansible.builtin.import_playbook: "{{ playbook_dir }}/sub/deploy.yml"
# Note: In the imported playbook, playbook_dir is STILL the original
# /project/playbooks — NOT /project/playbooks/sub/
Practical Examples
Multi-Environment Deployment
---
- name: Deploy application
hosts: "{{ target_hosts }}"
vars:
env_dir: "{{ playbook_dir }}/../environments/{{ env }}"
tasks:
- name: Load environment variables
ansible.builtin.include_vars:
dir: "{{ env_dir }}/vars"
- name: Deploy env-specific config
ansible.builtin.template:
src: "{{ env_dir }}/templates/app.conf.j2"
dest: /etc/myapp/app.conf
Portable Role with Local Files
---
- name: Setup monitoring
hosts: all
vars:
project_root: "{{ playbook_dir }}/.."
tasks:
- name: Copy dashboards
ansible.builtin.copy:
src: "{{ project_root }}/dashboards/{{ item }}"
dest: /var/lib/grafana/dashboards/
loop: "{{ lookup('fileglob', project_root + '/dashboards/*.json', wantlist=True) }}"
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
playbook_dir is empty | Bug in very old Ansible | Upgrade to 2.9+ |
| Path doesn't resolve | Relative .. gone wrong | Use realpath filter: {{ (playbook_dir + '/../files') | realpath }} |
| Different value in included playbook | import_playbook keeps original dir | Use explicit paths |
| Permission denied on path | User can't read playbook directory | Check filesystem permissions |
Best Practices
- Use
playbook_dirin playbooks,role_pathin roles — correct scope - Combine with
realpathfilter — resolves..to clean absolute paths - Define a
project_rootvar —{{ playbook_dir }}/..for cleaner references - Don't hardcode absolute paths — use magic variables for portability
- Document your directory structure — teammates need to know the layout
Conclusion
playbook_dir gives you the absolute path to your playbook's directory, making file references portable. Use it to load templates, vars files, and scripts relative to the playbook location. Combine with realpath filter for clean paths. Inside roles, prefer role_path instead. Define a project_root variable when you need frequent parent-directory references.