If you’re using vim-gutentags with Vim and struggling to exclude directories like node_modules, vendor, or themes from your tags file, you’re not alone—and the fix is simpler than you think.
The issue usually comes down to one thing: path format mismatch. vim-gutentags expects relative paths in your exclude patterns, but many users accidentally use absolute paths, causing ctags to ignore the exclusions entirely.
How to Confirm What Path Format vim-gutentags Uses
Add this line to your .vimrc to enable debug output:
let g:gutentags_trace = 1
When you open Vim, you’ll see a log like this:
... gutentags: Running: ['/path/to/update_tags.sh', ..., '-p', '.', '-x', 'vendor/*', '-x', 'themes/*', ...] gutentags: In: /your/project/root/ ...
Notice the -p .? That means vim-gutentags is running ctags with a relative path (.). Therefore, your exclude patterns must also be relative—not absolute.
❌ Wrong: Using Absolute Paths
let g:gutentags_ctags_exclude = [ \ '/home/user/project/vendor/*', \ '/home/user/project/themes/*', \ '/home/user/project/node_modules/*' \]
These won’t work because ctags is scanning from “.“, and it’s comparing excludes against relative paths like `vendor/`, not `/home/user/project/vendor/`.
✅ Correct: Use Relative Paths
let g:gutentags_ctags_exclude = [ \ 'vendor/*', \ 'themes/*', \ 'node_modules/*', \ 'build/*' \]
This matches exactly what ctags sees during traversal.
This behavior stems from how Universal Ctags processes command-line options and paths. If you’re using ctags directly (not through gutentags), remember that all --exclude flags must appear before the source path—otherwise they’re silently ignored. Learn more in our guide: Why Universal Ctags ignores your –exclude flags .
Why This Happens: It’s a ctags Behavior
Universal Ctags applies --exclude patterns against the relative file paths used during recursion. If you run:
ctags -R --exclude=$PWD/node_modules .
…it fails, because $PWD/node_modules (absolute) doesn’t match the relative path ./node_modules.
But this works:
ctags -R --exclude=node_modules .
vim-gutentags follows the same rule—so always use relative patterns in g:gutentags_ctags_exclude.
Pro Tip
Keep your exclude list clean and generic. This makes your .vimrc portable across projects:
let g:gutentags_ctags_exclude = [ \ 'node_modules/*', \ 'vendor/*', \ '.git/*', \ 'build/*', \ 'dist/*', \ '__pycache__/*' \]
Now your tags file stays lean, fast, and free of third-party noise.
Happy coding—and happy tagging!
PS. If you’re serious about mastering Vim—and making tools like ctags, gutentags, and tags navigation work for you, not against you—do yourself a favor and grab a copy of Practical Vim: Edit Text at the Speed of Thought . It’s the one book that will transform how you use Vim daily, and it’ll save you hours of frustration (and Stack Overflow rabbit holes).
amazing, had the same problem. But it was calling abs path