Neovim Directory Structure
Neovim defines a directory structure in which each folder serves a specific purpose. The contents of some directories are loaded automatically following a fixed order. Here I will only discuss the directories that are relevant for most users.
Load Files during Initialization
Traditionally, Vim was initialized by automatically executing the .vimrc
file at startup. Neovim follows the
XDG specification, which specifies the configuration directory via the XDG_CONFIG_HOME
environment variable. Before version 0.5, for most users this meant that ~/.vimrc
was replaced by ~/.config/nvim/init.vim
.
Since Lua was introduced as an alternative to Vimscript, Neovim can also be initialized via init.lua
. Note that init.lua
and init.vim
are mutually exclusive: If both files are present in the Neovim configuration directory, an error message will be displayed when the program is next started again (Conflicting configs
). In what follows I assume that the configuration is done with Lua and will ignore init.vim
and Vimscript-specific aspects.
If you want to keep your settings simple, you can store them all in init.lua
. However, to benefit from advanced features and to make it more manageable, configurations should be modularized across several files and directories.
In many YouTube guides and blog articles, the lua/
subdirectory is recommended for advanced configurations. However, Neovim offers additional subdirectories whose scripts are executed automatically and at earlier points during the initialization process.
In the following, I will limit myself to folders whose contents are to be executed. But helper functions and libraries can also be stored in the autoload/
subdirectory, from which they are only loaded but only called on demand.
plugin/
and after/plugin/
After init.lua
, the scripts in the plugin/
subdirectory are called. It is therefore a good place to store general configurations such as key mappings, color schemes or display options (e.g. line numbers). If you set a large number of such options, they can be split into different files, such as options.lua
or keymaps.lua
.
Some articles recommend plugin/
primarily for Vimscript. However, I could not find any references to this in the official documentation. As far as I can tell, there is no reason why Lua scripts should not be stored in this directory.
The after/plugin/
subdirectory is used to modify the standard behavior of existing plugins without changing their source code. In particular, this concerns plugins such as Telescope, NERDTree or Comment—applications that many users have in mind when they talk about “plugins”. Key assignments provide a case in point: If a plugin specifies standard key mappings, these can be overwritten by your own assignments in a file under after/plugin/
.
It is good practice to create a separate configuration file in after/plugin/
for each plugin used.
ftplugin/
and after/ftplugin/
The scripts in these subdirectories are similar to plugin/
or after/plugin/
, with the difference that the adjustments only apply to certain file types. For the changes to take effect, the name of the script must correspond to the desired content type, e.g. python.lua
or lua.lua
.
A common example is the configuration relating to tabs, which is handled differently depending on the language. For example, the style guides in Python usually require four spaces per tab, while Nix often only uses two.
The lua
Subdirectory
The lua
subdirectory makes it possible to set up the Neovim configuration in a modular and flexible fashion. If the scripts in this directory are called, this is done after the automatic calls discussed so far. In order for them to be executed at program start, however, a require(<filename>)
must be made in the init.lua
.
For instance, the file lua/plugins.lua
would be executed with require(plugins)
. Files in subdirectories can be included using either dot or slash notation: require(kai.plugins)
and require(kai/plugins)
are equivalent and call lua/kai/plugins.lua
.
An init.lua
in a subdirectory can be used to conveniently execute all the files within it. If lua/kai/
contains an init.lua
, you can use require(kai)
in the top-level init.lua
to load all the configurations in that subdirectory.
This structure makes it easier to create profiles. For this reason, the subdirectories under lua/
are often named as the user, as with user profiles. By creating direct subdirectories (such as lua/kai/
), you can easily manage different configurations and switch between profiles as required.