Syntax Highlighting for Nginx Config Files: Setup in VS Code and Vim
Nginx config files run deep with nesting and blocks; a single site routinely unfurls into dozens of lines of location. Without syntax highlighting, low-grade mistakes like an unclosed quote or a mismatched brace are hard to spot at a glance, and when nginx -t complains you have to hunt through the file line by line. This post gives editor-specific instructions for turning highlighting on: VS Code is a one-click install from the extension marketplace; Vim gets a 30-second recognition health check first — recent Vim versions have folded Nginx recognition into their bundled runtime, so it works out of the box, and only a failed check warrants copying the official syntax files from the Nginx source package (both paths fully tested).
Jump to the section for your editor:
- On VS Code → Section 1, done in two minutes;
- On Vim → Section 2, run the health check before deciding whether to install anything, with a control-group test and two real pitfalls attached.
VS Code: Install One Extension
VS Code’s built-in language support has no Nginx config, so an extension fills the gap. Open the extension marketplace (Ctrl+Shift+X), search nginx.conf, and install the one with high install counts. Two things to weigh when picking: first, update recency — Nginx directives grow year by year (such as grpc_pass and the http2 family), and a long-unupdated extension will flag those new directives as “unknown”; second, install count — an extension with millions of installs essentially never mislabels keywords.
No extra configuration is needed after installing: open any .conf file or a file under an nginx config path, and seeing the language mode in the bottom-right status bar read nginx means it’s active. If a .conf file isn’t auto-recognized, click the language mode in the status bar and pick nginx manually once; VS Code remembers the association.
For projects where config file names vary and you want a set-and-forget solution, use the workspace’s files.associations to batch-associate file name patterns with the nginx language:
1 | { |
Put it in .vscode/settings.json and commit it with the repo when the team shares one, so every collaborator opens the project in a highlight-ready state and nobody has to hand-pick the language mode.
Vim: Run the 30-Second Recognition Health Check First
Don’t rush to install anything. Recent Vim versions ship with Nginx syntax, indent, and filetype recognition built in — tested on vim 9.1 from Alpine 3.20 (no syntax files copied): nginx.conf, app.nginx, and configs under /etc/nginx/ all open as filetype=nginx, with syntax, indent, and filetype plugin all three present under /usr/share/vim/vim91/.
The health check takes one step — open any nginx config in Vim and ask for the file type:
1 | vim /etc/nginx/nginx.conf |
An output of filetype=nginx means the built-in recognition is working and you can skip the next two subsections entirely; an empty output or conf is the only case that requires reading on. To see the fuller picture, run a small comparison experiment: save the same server block under three file names and ask :set ft? of each — results below, measured for real.

| File name | :set ft? result |
Notes |
|---|---|---|
nginx.conf |
nginx | The main config name matches by default |
app.nginx |
nginx | The *.nginx suffix is the universal fallback |
app.conf |
conf | Arbitrary names go unrecognized — by design of the rules |
/etc/nginx/real.conf |
nginx | System config paths match first |
The most practical row in the table is the second: to get highlighting for loose config fragments you’ve split out yourself, just rename them with an .nginx suffix; dropping them into /etc/nginx/ works equally well. app.conf being recognized as conf is not a bug — the recognition rules match on file name and path, not by reading the content and guessing the language.
Vim: When Built-In Recognition Is Missing, Copy the Syntax Files from the Nginx Source Package
A failed health check usually means an older Vim. The orthodox remedy in that case has always been the contrib/vim/ directory of the Nginx source package — officially maintained by Nginx, updated with every release, with syntax rules that track nginx’s new directives, more reliable than third-party scripts.
First get the source package:
1 | curl -LO https://nginx.org/download/nginx-1.28.0.tar.gz |
contrib/vim/ contains four directories, each handling one job:
| Directory | Purpose |
|---|---|
syntax |
Highlighting rules (coloring of directives, strings, comments) |
indent |
Automatic indentation by server/location block |
ftdetect |
Decides which files are treated as nginx syntax |
ftplugin |
nginx-file-specific editing behavior (comment string, etc.) |
Then copy them wholesale into Vim’s runtime directory:
1 | mkdir -p /usr/share/vim/vimfiles/ |
Run mkdir before copying — don’t skip it. In an Alpine container, running cp -r directly fails with cp: can't create directory '/usr/share/vim/vimfiles/ftdetect': No such file or directory — the vimfiles directory isn’t pre-created on quite a few stripped-down systems, and its declaration in rpath doesn’t make it exist. The vim packages on distros like Debian and CentOS usually pre-create it, but adding mkdir -p is never wrong on any system. The full run record from tripping over the pitfall to a finished install:

After installing, rerun the health check above; :set ft? must turn into filetype=nginx before you can call it done. The ftdetect rules in contrib/vim are narrower than the newer Vim’s built-ins — in the 1.28.0 source package there are only four: the *.nginx suffix, a file name exactly nginx.conf, and the /etc/nginx/ and /usr/local/nginx/conf/ paths; the built-in rules additionally cover variants like nginx*.conf and */nginx/*.conf. If app.conf still goes unrecognized after copying, either rename it to .nginx or move it into /etc/nginx/.
A Pitfall in Headless Scenarios
Recognition triggers depend on Vim’s filetype machinery. In interactive use, mainstream distros turn it on — although Alpine’s default vimrc has no explicit filetype on line, interactive-mode tests still recognized all three files in the table above. The real trap is headless: the silent ex mode vim -es commonly used in scripts loads no vimrc at all, the filetype machinery never starts, and :set ft? outputs nothing; adding filetype detect explicitly to the command chain restores it (the health check itself was run as vim -es -c "filetype detect" -c "set ft?" -c q <filename>). If you batch-check file types in scripts, remembering this switch saves most of the troubleshooting time.
Two changes are noticeable the moment installation completes. First, structure becomes readable: block directives like server, location, and upstream pick up color, nesting levels stand out at a glance, and a dropped opening brace shows itself instantly as the rest of the file “goes color-wild.” Second, indentation automates: the indent script aligns new location blocks to their parent, saving every minute spent hand-typing spaces. As always, nginx -t after editing; highlighting’s job is to stop the low-grade errors at step one.
If it’s installed but still black-and-white, check three things in order: first, whether the file name trips a recognition rule (most common — renaming to .nginx verifies instantly); second, whether the filetype machinery was switched off by your own vimrc; third, that the copy destination is the same directory as one of the paths in set rtp? output — if the paths don’t line up, copying the files is the same as not copying them.
Caveats
- Extensions and syntax files affect only the editor’s display; they have no say over whether the config is correct. After saving changes and before reload,
nginx -tremains the non-negotiable verification step. contrib/vim/comes from the Nginx source package; before copying, confirm the current directory is the unpacked source root. Syntax files don’t auto-update when Nginx upgrades — re-copy them after significant version changes. On setups where the newer Vim already has built-in recognition, this whole step can be skipped.- Vim’s runtime directory varies by system and compile options;
vim -es -c 'set rtp?' -c qlists the actual search paths on your machine, and the copy destination can be any writable one from the output. - When editing configs on a server with no way to install syntax files,
nginx -terrors locate the problem themselves — in testing, putting aserverblock outsidehttp(single-line file/tmp/bad2.conf) producednginx: [emerg] "server" directive is not allowed here in /tmp/bad2.conf:1, with file name and line number right at the end. Read the line number and jump there; don’t count braces with the naked eye.
This article was rebuilt from the author’s CSDN blog posts written between 2020 and 2024, originally published on CSDN.