Introduction
Extra variables (--extra-vars or -e) pass variables to Ansible from the command line. They have the highest precedence — overriding all other variable definitions including role defaults, inventory vars, and play vars. Perfect for one-off runs, CI/CD pipelines, and environment-specific deployments.
Basic Usage
# Single variable
ansible-playbook deploy.yml -e "app_version=2.1.0"
# Multiple variables
ansible-playbook deploy.yml -e "app_version=2.1.0 env=production"
# Long form
ansible-playbook deploy.yml --extra-vars "app_version=2.1.0"
Variable Formats
Key=Value (Simple)
ansible-playbook site.yml -e "target_host=web-01 app_port=8080"
JSON Format
# Inline JSON
ansible-playbook site.yml -e '{"app_version": "2.1.0", "debug": true}'
# Complex structures
ansible-playbook site.yml -e '{"users": ["alice", "bob"], "config": {"port": 8080, "workers": 4}}'
YAML Format
ansible-playbook site.yml -e '{app_version: 2.1.0, debug: true}'
From File (@)
# JSON file
ansible-playbook site.yml -e @vars/production.json
# YAML file
ansible-playbook site.yml -e @vars/production.yml
# Multiple files
ansible-playbook site.yml -e @vars/common.yml -e @vars/production.yml
vars/production.yml:
env: production
app_version: "2.1.0"
db_host: prod-db.example.com
replicas: 3
debug: false
vars/production.json:
{
"env": "production",
"app_version": "2.1.0",
"db_host": "prod-db.example.com"
}
Variable Precedence
Extra vars have the highest precedence (position 22 of 22):
1. command line values (not variables)
2. role defaults
3. inventory file/script group vars
4. inventory group_vars/all
5. inventory group_vars/*
6. inventory file/script host vars
7. inventory host_vars/*
8. host facts / cached set_facts
9. play vars
10. play vars_prompt
11. play vars_files
12. role vars
13. block vars
14. task vars
15. include_vars
16. set_facts / registered vars
17. role params
18. include params
19. extra vars (HIGHEST) ← --extra-vars
This means -e always wins:
# playbook.yml
- hosts: all
vars:
app_port: 3000 # This gets overridden
tasks:
- debug:
msg: "Port: {{ app_port }}"
# Extra var wins
ansible-playbook playbook.yml -e "app_port=8080"
# Output: "Port: 8080"
Practical Patterns
CI/CD Pipeline
# GitLab CI / GitHub Actions
ansible-playbook deploy.yml \
-e "app_version=${CI_COMMIT_TAG}" \
-e "env=${CI_ENVIRONMENT_NAME}" \
-e "deployed_by=${GITLAB_USER_LOGIN}" \
-e "commit_sha=${CI_COMMIT_SHA}"
Environment Selection
# Development
ansible-playbook site.yml -e @vars/dev.yml
# Staging
ansible-playbook site.yml -e @vars/staging.yml
# Production (with override)
ansible-playbook site.yml -e @vars/prod.yml -e "replicas=5"
Target Specific Host
# Override target host
ansible-playbook deploy.yml -e "target_host=web-03"
# playbook.yml
- hosts: "{{ target_host | default('webservers') }}"
tasks: ...
Dynamic Values
# Current timestamp
ansible-playbook deploy.yml -e "deploy_time=$(date +%Y%m%d-%H%M%S)"
# Git info
ansible-playbook deploy.yml -e "git_branch=$(git rev-parse --abbrev-ref HEAD) git_sha=$(git rev-parse --short HEAD)"
# Read from file
ansible-playbook deploy.yml -e "api_key=$(cat secrets/api_key.txt)"
Boolean and Numeric Values
# Booleans — use JSON format for correct typing
ansible-playbook site.yml -e '{"debug": true, "force_deploy": false}'
# Or key=value (treated as strings — may need | bool filter)
ansible-playbook site.yml -e "debug=true"
# In playbook — handle both formats
- debug:
msg: "Debug mode"
when: debug | default(false) | bool
Lists and Dictionaries
# Lists
ansible-playbook site.yml -e '{"packages": ["nginx", "redis", "git"]}'
# Dictionaries
ansible-playbook site.yml -e '{"database": {"host": "db.local", "port": 5432, "name": "myapp"}}'
Require Extra Variables
# Fail if variable not provided
- name: Validate required variables
ansible.builtin.assert:
that:
- app_version is defined
- env is defined
fail_msg: "Required: -e 'app_version=X.Y.Z env=production'"
# Or use vars_prompt as fallback
- hosts: all
vars_prompt:
- name: app_version
prompt: "App version to deploy"
private: false
Multiple -e Flags
Later -e flags override earlier ones:
# base.yml sets debug=false
# But inline override sets debug=true (wins)
ansible-playbook site.yml -e @vars/base.yml -e "debug=true"
With Ansible Ad-Hoc
# Ad-hoc with extra vars
ansible all -m debug -a "msg={{ greeting }}" -e "greeting='Hello World'"
# Install specific version
ansible webservers -m apt -a "name=nginx={{ nginx_version }}" -e "nginx_version=1.24.0" --become
Security Considerations
# ⚠️ Passwords on command line are visible in process list
# BAD
ansible-playbook site.yml -e "db_password=secret123"
# BETTER — use file
ansible-playbook site.yml -e @secrets/db.yml
# BEST — use Ansible Vault
ansible-playbook site.yml -e @secrets/db.vault.yml --ask-vault-pass
Troubleshooting
Variable Not Being Used
# Check precedence — debug all variables
ansible-playbook site.yml -e "app_port=8080" -v
# Look for "app_port" in output
# Verify variable value
ansible all -m debug -a "var=app_port" -e "app_port=8080"
JSON Parse Error
# ❌ Wrong — single quotes inside JSON on some shells
ansible-playbook site.yml -e "{'key': 'value'}"
# ✅ Correct — use proper JSON with double quotes
ansible-playbook site.yml -e '{"key": "value"}'
# ✅ Or use a file
ansible-playbook site.yml -e @vars.json
Related Articles
Conclusion
Extra vars (-e) are the highest-precedence variables in Ansible — they override everything. Use them for: CI/CD pipeline values, environment selection (-e @vars/prod.yml), one-off overrides, and dynamic values from shell commands. Use @file syntax for complex structures and secrets. Always use assert to validate required extra vars in playbooks. Avoid passing secrets directly on the command line — use vault-encrypted files instead.