Open-Source Wikis

/

Neovim

/

How to contribute

/

Development workflow

neovim/neovim

Development workflow

The day-to-day cycle that turns a clean checkout into a merged PR.

1. Branch

Always work on a feature branch, never on master. CONTRIBUTING.md is explicit about this.

git checkout master
git pull origin master
git checkout -b fix/lsp-progress-leak

Set the blame ignore file once per clone so git blame skips the bulk-format commits:

git config blame.ignoreRevsFile .git-blame-ignore-revs

2. Build

For active development use a debug build:

make CMAKE_BUILD_TYPE=Debug

For a quick rebuild after editing C, just run make again — Ninja will only rebuild touched translation units. After editing the Lua data files (options.lua, eval.lua, ex_cmds.lua, auevents.lua, vvars.lua, keycodes.lua) or the API headers, you also have to rebuild because the C tree consumes generated headers.

Edits under runtime/lua/vim/_core/ are precompiled to bytecode. To iterate without rebuilding, run with --luamod-dev:

VIMRUNTIME=./runtime ./build/bin/nvim --luamod-dev

3. Test

Before committing, run the relevant tests locally. The two paths in order of speed:

TEST_FILE=test/functional/lua/diagnostic_spec.lua make functionaltest
TEST_FILTER='vim.diagnostic.set' make functionaltest
make functionaltest    # the full functional suite, slower
make unittest          # FFI-based unit tests
make test              # everything

The full matrix (oldtest, valgrind, ASAN/UBSAN) runs in CI on every push. Reproduce locally only when you have to.

4. Lint and format

Before pushing:

make format            # apply clang-format/stylua to changed files
make lint              # all linters
make lintdoc           # if you changed runtime/doc/*.txt

make lint runs the same checks that CI runs. If it passes locally and CI fails, the most common reason is a stale .deps/ directory — make distclean && make usually fixes it.

5. Commit

Use conventional commits. The structure is:

type(scope): short imperative subject

Problem:
What's broken or missing, in one or two sentences.

Solution:
How this commit fixes it, in one or two sentences.

Types in active use: build, ci, docs, feat, fix, perf, refactor, revert, test, vim-patch. Scopes are free-form but conventional ones are lsp, treesitter, tui, lua, api, extmark, float, lint, vim-patch, etc.

If AI was used in any capacity to produce the change, append a trailer (AGENTS.md):

AI-assisted: <tool name>

For breaking changes, use ! and add a BREAKING CHANGE: footer:

refactor(provider)!: drop support for Python 2

BREAKING CHANGE: refactor to use Python 3 features since Python 2 is no longer supported.

make lintcommit validates the commit message format.

6. Push and open PR

Push to your fork, open a PR against neovim/neovim:master. Mark it as Draft until you're done iterating.

git push -u origin fix/lsp-progress-leak
gh pr create --draft --base master

Title format follows the commit message. PR description ≈ commit body. Tests are required; mark the box.

7. Address review

Force-pushing onto your branch is fine and expected. Maintainers will pull the latest tip; there's no need to add review-fixup commits unless the change is large.

When the PR is ready:

  • Squash-merge for single-meaningful-commit PRs.
  • Merge (no squash) for multi-commit PRs that should preserve their structure.

Maintainers make the merge call.

Source navigation tips

The repo is large enough that grep-and-pray is not always enough. The recommended setup:

  • Build with compile_commands. build/compile_commands.json is generated by CMake. The repo's .clangd file points at it; any LSP-aware editor (including Neovim itself with nvim-lspconfig) gets cross-file go-to-def.
  • Use clangd. It is the LLM of cross-references — it indexes the whole tree, including generated headers in build/src/nvim/auto/.
  • runtime/doc/dev_arch.txt is the architecture map. It is short, dense, and current. Read it before deep diving.
  • Read top-of-file comments. Module-specific notes live at the top of terminal.c, undo.c, marktree.c, memline.c, regexp.c, etc. They are usually short and pointed.

Working with Vim patches

A non-trivial fraction of commits are vim-patch: — porting a single change from upstream Vim. The workflow is documented in runtime/doc/dev_vimpatch.txt. The driver script is scripts/vim-patch.sh. Subjects look like vim-patch:9.2.0416: ... so they are easy to grep for.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Development workflow – Neovim wiki | Factory