home / skills / kriscard / kriscard-claude-plugins / neovim-best-practices

This skill guides configuring Neovim with Lua, lazy.nvim, and modular structure to boost performance, maintainability, and productive plugin development.

npx playbooks add skill kriscard/kriscard-claude-plugins --skill neovim-best-practices

Review the files below or copy the command above to add this skill to your agents.

Files (6)
SKILL.md
3.9 KB
---
name: neovim-best-practices
description: >-
  Configures Neovim with the user's opinionated Lua patterns, namespaced config
  structure, LSP via Mason + nvim-lspconfig, and leader key conventions. Contains
  user-specific decisions and checklists Claude cannot know without this skill.
  Make sure to use this skill whenever the user mentions neovim, nvim, init.lua,
  LSP setup, keymaps, autocommands, neovim plugins, Mason, TypeScript LSP, slow
  LSP, neovim config, or any neovim question — even if Claude thinks it can
  answer from general knowledge.
version: 0.1.0
---

# Neovim Best Practices

Opinionated guidance for modern Neovim configuration. This skill covers the decisions and patterns that matter — not documentation you can look up.

## Core Decisions

These are the opinionated choices this config follows. Apply these unless the user explicitly wants something different.

### Lua Only, No Vimscript

All configuration in Lua. No `vim.cmd()` wrappers around Vimscript unless there's no Lua API equivalent. Use `vim.opt` for options, `vim.keymap.set` for keymaps, `vim.api.nvim_create_autocmd` for autocommands.

### lazy.nvim for Plugin Management

One plugin per file in `lua/plugins/`. Every plugin lazy-loaded unless needed at startup (colorscheme, treesitter, statusline). See the `lazy-nvim-optimization` skill for deep lazy-loading guidance.

### Namespace Under Username

```
~/.config/nvim/
├── init.lua
└── lua/
    └── kriscard/
        ├── init.lua
        ├── options.lua
        ├── keymaps.lua
        ├── autocmds.lua
        └── lazy.lua
```

This prevents collisions with plugin module names. Entry point is just `require("kriscard")`.

### LSP via Mason + nvim-lspconfig

Mason manages server installations. nvim-lspconfig provides server configurations. Use `cmp_nvim_lsp` capabilities for completion integration. Set keymaps in `on_attach` so they're buffer-local.

### Leader Key Conventions

`<Space>` as leader, set before any plugins load. Organized by prefix:
- `f` = find/search (telescope)
- `g` = git operations
- `b` = buffer management
- `w` = window management
- `l` = LSP operations
- `t` = terminal/tests

Every keymap requires a `desc` field for which-key discoverability.

## Version-Specific Features (0.10+)

Take advantage of these — they replace plugins:

- **Built-in commenting**: `gcc`/`gc` work natively. Can replace Comment.nvim.
- **Inlay hints**: `vim.lsp.inlay_hint.enable(true)` — no plugin needed.
- **Improved diagnostics**: `vim.diagnostic.config()` with `float.border` for better display.

## Deprecated Patterns to Avoid

| Instead of... | Use... |
|---------------|--------|
| `vim.cmd("set number")` | `vim.opt.number = true` |
| `vim.api.nvim_set_keymap()` | `vim.keymap.set()` |
| `vim.cmd("augroup...")` | `vim.api.nvim_create_autocmd()` |
| Vimscript autocommands | Lua with `callback` |
| Comment.nvim (on 0.10+) | Built-in `gcc` |

## Checklists

### Config Structure

- [ ] `init.lua` is entry point only (just `require("kriscard")`)
- [ ] Config namespaced under username in `lua/`
- [ ] Plugin specs in `lua/plugins/` (one per file or logical group)
- [ ] Options, keymaps, autocmds in separate files
- [ ] Using lazy.nvim for plugin management

### Code Quality

- [ ] All config in Lua (no Vimscript)
- [ ] `vim.opt` for options
- [ ] `vim.keymap.set` with `desc` for keymaps
- [ ] `vim.api.nvim_create_autocmd` for autocommands
- [ ] No deprecated APIs
- [ ] Leader key set before plugin loading

### Performance

- [ ] Startup under 50ms (`nvim --startuptime`)
- [ ] Plugins lazy-loaded by cmd/keys/ft/event
- [ ] Heavy plugins deferred with `VeryLazy`
- [ ] No synchronous system calls at startup

## Reference Files

For detailed information:
- **`references/plugin-recommendations.md`** - Curated plugin list by category
- **`references/lsp-setup.md`** - Comprehensive LSP configuration guide
- **`references/migration-guide.md`** - Migrating from Vimscript to Lua

Overview

This skill provides concise, practical guidance for configuring Neovim using Lua, organizing your config, and setting up built-in LSP. It focuses on maintainable structure, performant plugin loading, and modern API patterns for Neovim 0.5+. Use it when creating or refactoring a Neovim setup or writing Lua plugins.

How this skill works

The skill inspects recommended file and module layouts, common configuration patterns (options, keymaps, autocommands), and LSP on-attach patterns. It highlights Lua-first practices, namespacing to avoid collisions, plugin selection criteria, and performance strategies like lazy-loading and startup profiling. It does not cover other editors or editor-specific tooling.

When to use it

  • Starting a new Neovim config or migrating from Vimscript to Lua
  • Organizing config into modules: options, keymaps, autocmds, and plugins
  • Setting up Neovim's built-in LSP with nvim-lspconfig and mason
  • Improving startup time through lazy-loading and profiling
  • Writing portable Lua plugins or utility modules for your config

Best practices

  • Keep init.lua minimal and namespace all modules under lua/<yourname>/
  • Use Lua APIs: vim.opt for options, vim.keymap.set for mappings, nvim_create_autocmd for events
  • Prefer Lua functions and descriptive keymap 'desc' for discoverability and which-key integration
  • Select plugins by maintenance, minimal dependencies, performance, and documentation
  • Lazy-load plugins by command, keymap, filetype, or event; measure startup with --startuptime
  • Avoid hardcoded paths; use vim.fn.stdpath('config'|'data') for portability

Example use cases

  • Create a clean config layout: init.lua -> require('<you>') -> lua/<you>/{options,keymaps,autocmds,plugins}
  • Configure LSP: install mason, ensure servers, set capabilities via cmp_nvim_lsp, and apply on_attach keymaps
  • Optimize startup: move nonessential plugins to lazy-load on events or keys and profile startup time
  • Write a small util module for shared LSP handlers and use it across server setups
  • Replace legacy autocommand strings with nvim_create_autocmd callbacks for clarity and safety

FAQ

Should I still use Vimscript anywhere?

Prefer Lua for all new config; only keep Vimscript for legacy snippets you cannot port yet, and plan to migrate them.

How do I avoid plugin conflicts?

Namespace your modules, lazy-load plugins when appropriate, prefer plugins that use Neovim's Lua API, and isolate plugin configs under lua/plugins/.