# ansible-vim: Ansible syntax highlighting for Vim and Neovim

> ansible-vim is a Vim plugin that highlights Ansible YAML playbooks, Jinja2 templates and hosts files by extending the original YAML and Jinja syntax rather than replacing it, with a separate tree-sitter path for Neovim 0.12 and later. It is a highlighting layer, not a linter, and some of its limits are deliberate.

**pearofducks/ansible-vim** — A vim plugin for syntax highlighting Ansible's common filetypes

- Repository: https://github.com/pearofducks/ansible-vim
- Stars: 821 · Forks: 95
- Language: Vim Script
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/pearofducks-ansible-vim

## It extends the original syntax instead of replacing it

There is a design decision at the centre of this plugin, and the documentation states it directly. The plugin sources the original formats and simply modifies the highlights as appropriate, and that is presented as the reason it should be reliable. The stated benefit is a focus on simplicity and configurability instead of patching bad syntax detection.

That is worth understanding, because it explains what the plugin does not do. It does not define a new syntax for Ansible. It takes the YAML syntax that already exists in your editor and adds Ansible awareness on top of it: module keywords, the name: key that modules use for self-documentation, and the key=value attribute syntax that Ansible modules use inside playbooks. Jinja2 templates get the same treatment, and files named hosts get the hosts file handling.

The audience is a Vim or Neovim user who writes Ansible and wants the editor to understand the domain a little. The plugin is written in Vim Script, it covers Ansible 2.x, and the licence is MIT. The repository is small and readable: UltiSnips, ftdetect, ftplugin, indent, lua, queries, syntax, tests, and a Makefile.

What it is not is a linter or a validator. Nothing here checks that your playbook is correct, and the plugin never talks to Ansible itself. The one place it comes closest is the UltiSnips generation script, which is discussed later.

## Detection is folder names and file suffixes

Because the plugin extends existing syntax, it has to decide when to extend it, and that decision is a set of fairly literal rules.

A YAML file is treated as a playbook if it sits in a group_vars or host_vars folder, if it is in a tasks, roles or handlers folder and has a .yml or .yaml suffix, or if it is named playbook.yml, site.yml, main.yml, or the .yaml variants of those. A file with a .j2 suffix is a Jinja2 template. A file named hosts is an Ansible hosts file.

When the rules do not match your layout, you can set the filetype by hand with :set ft=yaml.ansible, or use the jinja2 and ansible_hosts filetypes, and the documentation suggests adding a rule of your own in your .vimrc for a custom pattern:

```vim
au BufRead,BufNewFile */playbooks/*.yml set filetype=yaml.ansible
```

Overriding the defaults works the same way, with an augroup so your autocommand does not pile up on repeated sourcing:

```vim
augroup ansible_vim_fthosts
  autocmd!
  autocmd BufNewFile,BufRead hosts setfiletype yaml.ansible
augroup END
```

The example given is a team that uses YAML syntax for its hosts file and wants those files highlighted as Ansible YAML. Note the filetype named in the manual note, :set ft=ruby.jinja2, which looks like a leftover from an earlier approach and is worth testing rather than trusting.

## Neovim 0.12 takes a different road entirely

The plugin has two implementations, and the newer one is not a port of the older one.

For Neovim 0.12 and later, the plugin provides tree-sitter based highlighting with Jinja2 template expression support and semantic Ansible keyword highlighting, and it is installed with the built-in package manager:

```vim
vim.pack.add({ 'pearofducks/ansible-vim' })
```

The lua and queries directories at the top of the repository are that implementation: a Lua module with a setup function, and tree-sitter queries. The Makefile shows how the pieces fit together. The test target runs Neovim headless with the runtime path extended to a sibling checkout of nvim-treesitter, turns on filetype, plugin and indent detection, calls require("ansible").setup(), sets the filetype to ansible, and then executes a Lua highlight test file. There is also a try target that opens a test playbook with a viewer and a try-clean target that starts with no configuration, which is the honest way to check the plugin in isolation.

The practical consequence is that the classic and tree-sitter paths will not behave identically, and a feature that exists in one may not exist in the other. The documentation points to a separate neovim section for setup instructions, which is where the differences are meant to be reconciled.

## Five ways to install, and two of them are distro packages

Installation is well covered, which is not unusual for a Vim plugin but does make the choice easy.

For vim-plug, the declaration is a single line:

```vim
Plug 'pearofducks/ansible-vim'
```

There is also a variant with a post-update hook, shown in the documentation as a Plug line with a do key pointing at ./UltiSnips/generate.sh, which regenerates the snippets after every update. That variant is worth understanding before you use it, because the script is where the plugin touches Ansible.

Vundle uses Plugin 'pearofducks/ansible-vim'. Pathogen is installed by cloning into your bundle directory:

```bash
git clone https://github.com/pearofducks/ansible-vim ~/.vim/bundle/ansible-vim
```

Neovim's own package layout works too, by cloning into the start directory of a pack path:

```bash
git clone https://github.com/pearofducks/ansible-vim.git "${HOME}/.vim/pack/plugins/start/ansible-vim"
```

And for people who would rather not manage a plugin at all, there is a vim-ansible package in the Arch community repository, in the default Fedora repository, and in EPEL for RHEL and CentOS.

## The snippet generator needs a recent Ansible

The UltiSnips part deserves its own section, because the documentation attaches a real caveat to it.

The snippets are not checked in as static files. They are generated by a script, generate.sh, which you can point at with the vim-plug post-update hook. Two notes follow. The first is that because of Ansible API changes, generate.sh may require the latest or near-latest version of Ansible, which is a dependency the README is stating plainly: this script talks to Ansible, and it will break against an old installation. The second is that the script can receive parameters, with the details in the UltiSnips Readme in the repository.

So the trade is explicit. If you want the snippets, you need a current Ansible on the machine that runs the update, and the generation runs on every plugin update rather than once. If you do not need the snippets, you can install without the hook and keep the plugin purely as a highlighting layer with no dependency on Ansible being present at all.

The repository also carries a post-update hook note aimed at exactly this kind of user, and the UltiSnips directory is where the snippet definitions and the script live.

## The options are flag strings, and most default to subtle

The configuration surface is a set of global variables, and the defaults are deliberately quiet.

g:ansible_attribute_highlight controls the key=value module attributes and the same syntax in hosts files. It takes a flag string, and the documentation marks the defaults in bold: o highlights only instances of key= found on newlines, and b brightens them. The other flags are a for all instances, d to dim, and n to turn the highlight off completely.

g:ansible_name_highlight does the same for the name: key that modules use for self-documentation, and it is off by default, with d and b as the two choices.

g:ansible_extra_keywords_highlight is enabled when set and disabled when not, and it lights up a long list of additional keywords including the become family, check_mode, diff, no_log, delegate_to, ignore_errors, max_fail_percentage, gather_facts, async, poll, throttle, timeout, run_once and serial. The default set is smaller and covers the module keywords, the include and import family, when, changed_when, failed_when, block, rescue, always, notify, listen, register, the pre_tasks and post_tasks style keys, and the loop keywords including with_.+, loop, loop_control, until, retries and delay.

The group names are configurable too, and each accepts any syntax group name from :help E669. g:ansible_extra_keywords_highlight_group defaults to Structure, while g:ansible_fqcn_highlight and g:ansible_normal_keywords_highlight default to Statement, and both fall back to Statement when not set. Two smaller ones round it out: g:ansible_unindent_after_newline resets indentation to column zero after two newlines in insert mode, which departs from normal YAML behaviour, and g:ansible_yamlKeyName exists for compatibility with stephpy/vim-yaml.

## The FQCN dot is deliberately left to Vim

There is one gap the documentation is unusually candid about, and it is worth knowing before you file a bug.

Ansible fully qualified collection names contain a dot, as in a namespaced collection name. The plugin notes that the dot in the FQCN can also be highlighted, but only through a modification to a Vim syntax internal, and that this plugin will not do it automatically. In other words, the dot is left alone unless you patch Vim's own syntax handling, which the documentation links to a discussion of the technique.

That is a small thing, and it points at the plugin's overall philosophy: it extends rather than replaces, and where the underlying syntax engine has a limitation, the plugin does not work around it by rewriting the engine. The same reasoning explains the naming of the option for compatibility with another YAML plugin, which exists to interoperate rather than to fork.

The alternative to all of this is to use a plain YAML plugin and add the Ansible awareness yourself through ftplugin files and matchadd calls, which gives complete control and no dependency, but means every team member has to carry that configuration. ansible-vim's value is that the same awareness is available to everyone who installs it, and that its behaviour is documented rather than improvised.

## Conclusion

ansible-vim suits a team editing Ansible on a small screen or over SSH who wants module keywords and name keys to stand out without leaving Vim, and it is the wrong tool for a team that wants validation, because it highlights and never checks your playbooks. Verify first which path your editor takes, since Neovim 0.12 and later use the tree-sitter implementation under queries/ and lua/ while older setups use the classic syntax files, and note that the release history jumps from 3.4 in 2023 straight to 4.0 in April 2026, so the version you install changes what you get.

## FAQ

### How do I install ansible-vim in Vim or Neovim?

With vim-plug, add Plug 'pearofducks/ansible-vim'. Neovim 0.12 and later can use vim.pack.add({ 'pearofducks/ansible-vim' }). There are also pathogen, vundle, vim packages, and distro packages named vim-ansible for Arch, Fedora, RHEL and CentOS.

### How does ansible-vim decide that a YAML file is an Ansible playbook?

A YAML file is treated as a playbook when it is in a group_vars or host_vars folder, when it is in a tasks, roles or handlers folder with a .yml or .yaml suffix, or when it is named playbook.yml, site.yml, main.yml or their .yaml equivalents. Files with a .j2 suffix are Jinja2 templates, and files named hosts are treated as hosts files.

### What does the UltiSnips generate.sh script do in ansible-vim?

It generates the plugin's snippet definitions, and the documentation recommends running it through a vim-plug post-update hook. Because of Ansible API changes, generate.sh may require the latest or near-latest version of Ansible, and it can take parameters documented in the UltiSnips Readme.

### Which options does ansible-vim expose?

Global variables such as g:ansible_attribute_highlight, g:ansible_name_highlight, g:ansible_extra_keywords_highlight, g:ansible_extra_keywords_highlight_group, g:ansible_fqcn_highlight, g:ansible_normal_keywords_highlight, g:ansible_unindent_after_newline and g:ansible_yamlKeyName. The highlight group options accept any syntax group name listed in :help E669.

### Does ansible-vim validate playbooks or check for errors?

No. It is a syntax highlighting plugin that extends the original YAML and Jinja2 formats with Ansible awareness. The only component that talks to Ansible itself is the snippet generation script, and the README does not document any linting or validation feature.

## Sources

- [Issues](https://github.com/pearofducks/ansible-vim/issues)
- [License: MIT](https://github.com/pearofducks/ansible-vim/blob/master/LICENSE)
- [pearofducks/ansible-vim on GitHub](https://github.com/pearofducks/ansible-vim)
- [README](https://github.com/pearofducks/ansible-vim/blob/master/README.md)
- [Releases](https://github.com/pearofducks/ansible-vim/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pearofducks-ansible-vim
