Skip to content

Neovim: Modern Vim with LSP and Plugin Configuration

DodaTech Updated 2026-06-22 6 min read

In this tutorial, you'll learn Neovim setup including Lua configuration, LSP integration, treesitter, autocompletion, and plugin management for a modern IDE-like editing experience in the terminal.

Why Neovim Matters

Modern development demands modern tooling. Neovim brings the speed and modal editing of Vim together with Language Server Protocol support, asynchronous plugins, and a Lua-based configuration system. It gives you an IDE experience inside the terminal without the bloat of Electron-based editors.

By the end of this guide, you will have a fully configured Neovim setup with LSP, autocompletion, treesitter, and a plugin manager.

What is Neovim?

Neovim is a fork of Vim that reimagines the editor for modern workflows. It introduces a Lua scripting API, an embedded terminal, a job control system, and native LSP client support.

flowchart LR
  A[Neovim] --> B[Lua Config]
  A --> C[Lazy.nvim Plugin Manager]
  C --> D[Treesitter]
  C --> E[LSP Config]
  C --> F[nvim-cmp Autocompletion]
  D --> G[Syntax Highlighting]
  D --> H[Code Navigation]
  E --> I[Diagnostics]
  E --> J[Go to Definition]
  F --> K[Completion Menu]

Installation

# macOS
brew install neovim

# Ubuntu/Debian
sudo apt install neovim -y

# Verify
nvim --version
# NVIM v0.10.0

Lua Configuration

Neovim configuration lives in ~/.config/nvim/. The main entry point is ~/.config/nvim/init.lua.

# Create the config directory
mkdir -p ~/.config/nvim

Basic init.lua

-- ~/.config/nvim/init.lua
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.smartindent = true
vim.opt.wrap = false
vim.opt.swapfile = false
vim.opt.backup = false
vim.opt.undodir = os.getenv("HOME") .. "/.vim/undodir"
vim.opt.undofile = true
vim.opt.hlsearch = true
vim.opt.incsearch = true
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.scrolloff = 8
vim.opt.signcolumn = "yes"
vim.opt.updatetime = 50
vim.opt.colorcolumn = "80"

Plugin Manager: Lazy.nvim

Lazy.nvim is the most popular Neovim plugin manager. It handles installation, updates, and lazy-loading.

git clone https://github.com/folke/lazy.nvim.git \
  ~/.local/share/nvim/lazy/lazy.nvim

Plugin Configuration

-- ~/.config/nvim/init.lua
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
  -- Treesitter
  {
    "nvim-treesitter/nvim-treesitter",
    build = ":TSUpdate",
    config = function()
      require("nvim-treesitter.configs").setup({
        ensure_installed = {"lua", "python", "javascript", "typescript", "rust", "c", "cpp"},
        auto_install = true,
        highlight = { enable = true },
        indent = { enable = true },
      })
    end,
  },

  -- LSP Configuration
  {
    "neovim/nvim-lspconfig",
    config = function()
      require("lspconfig").lua_ls.setup({})
      require("lspconfig").pyright.setup({})
      require("lspconfig").tsserver.setup({})
    end,
  },

  -- Autocompletion
  {
    "hrsh7th/nvim-cmp",
    dependencies = {
      "hrsh7th/cmp-nvim-lsp",
      "hrsh7th/cmp-buffer",
      "hrsh7th/cmp-path",
    },
    config = function()
      local cmp = require("cmp")
      cmp.setup({
        mapping = cmp.mapping.preset.insert({
          ["<C-b>"] = cmp.mapping.scroll_docs(-4),
          ["<C-f>"] = cmp.mapping.scroll_docs(4),
          ["<C-Space>"] = cmp.mapping.complete(),
          ["<C-e>"] = cmp.mapping.abort(),
          ["<CR>"] = cmp.mapping.confirm({ select = true }),
        }),
        sources = cmp.config.sources({
          { name = "nvim_lsp" },
          { name = "buffer" },
          { name = "path" },
        }),
      })
    end,
  },
})

LSP Configuration Details

The built-in LSP client connects to language servers for diagnostics, autocompletion, and code actions.

-- Key mappings for LSP
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Go to definition" })
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover documentation" })
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, { desc = "Go to implementation" })
vim.keymap.set("n", "gr", vim.lsp.buf.references, { desc = "Show references" })
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, { desc = "Rename symbol" })
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "Code action" })
vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Previous diagnostic" })
vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Next diagnostic" })
vim.keymap.set("n", "<leader>e", vim.diagonstic.open_float, { desc = "Open diagnostic float" })

Installing Language Servers

Install language servers with your system package manager or npm:

# Python
npm i -g pyright

# TypeScript/JavaScript
npm i -g typescript typescript-language-server

# Lua
brew install lua-language-server

# Rust
brew install rust-analyzer

Treesitter

Treesitter provides better syntax highlighting and code navigation by Parsing your code into a syntax tree.

Expected Behavior

With Treesitter enabled:

  • Code is highlighted more accurately than regex-based highlighting
  • % jumps between matching brackets and keywords
  • [m and ]m jump between function boundaries
  • Code folding works at the syntax level
-- Additional Treesitter features
require("nvim-treesitter.configs").setup({
  incremental_selection = {
    enable = true,
    keymaps = {
      init_selection = "gnn",
      node_incremental = "grn",
      node_decremental = "grm",
    },
  },
  textobjects = {
    select = {
      enable = true,
      lookahead = true,
      keymaps = {
        ["af"] = "@function.outer",
        ["if"] = "@function.inner",
        ["ac"] = "@class.outer",
        ["ic"] = "@class.inner",
      },
    },
  },
})

Autocompletion with nvim-cmp

nvim-cmp provides a configurable completion engine:

-- Additional completion sources
require("cmp").setup({
  snippet = {
    expand = function(args)
      vim.fn["vsnip#anonymous"](args.body)
    end,
  },
  window = {
    completion = cmp.config.window.bordered(),
    documentation = cmp.config.window.bordered(),
  },
  formatting = {
    fields = { "kind", "abbr", "menu" },
    format = function(entry, vim_item)
      vim_item.menu = ({
        nvim_lsp = "[LSP]",
        buffer = "[Buf]",
        path = "[Path]",
      })[entry.source.name]
      return vim_item
    end,
  },
})

File Explorer: Neo-tree

require("lazy").setup({
  {
    "nvim-neo-tree/neo-tree.nvim",
    branch = "v3.x",
    dependencies = {
      "nvim-lua/plenary.nvim",
      "nvim-tree/nvim-web-devicons",
      "MunifTanjim/nui.nvim",
    },
    config = function()
      require("neo-tree").setup({
        filesystem = {
          filtered_items = {
            visible = false,
            hide_dotfiles = false,
            hide_gitignored = false,
          },
        },
      })
      vim.keymap.set("n", "<leader>e", ":Neotree toggle<CR>")
    end,
  },
})

Color Scheme

require("lazy").setup({
  {
    "catppuccin/nvim",
    name = "catppuccin",
    priority = 1000,
    config = function()
      require("catppuccin").setup({
        flavour = "mocha",
        transparent_background = true,
      })
      vim.cmd.colorscheme("catppuccin")
    end,
  },
})

Common Errors

Problem Cause Fix
LSP not attaching to buffer Language server not installed Install the server for your language (e.g., npm i -g pyright)
Treesitter highlighting broken Parser not installed Run :TSInstall <language>
nvim-cmp not showing completions Missing sources Add cmp-nvim-lsp and configure LSP capabilities
Plugin not found by Lazy.nvim Wrong directory Ensure plugin spec is correct in require("lazy").setup()
Neovim hangs on startup Corrupted plugin Delete ~/.local/share/nvim/lazy/ and reinstall

Practice Questions

1. Where does Neovim read its main configuration from?

~/.config/nvim/init.lua.

2. What does the nvim-treesitter plugin provide?

Better syntax highlighting, code folding, and structure-based navigation.

3. How do you go to a symbol's definition in Neovim with LSP?

Press gd in normal mode.

4. What is Lazy.nvim used for?

Plugin management: installing, updating, and lazy-loading Neovim plugins.

5. How do you install a language server for Python in Neovim?

Run npm i -g pyright, then configure it with require("lspconfig").pyright.setup({}).

Challenge

Create a Neovim configuration from scratch with LSP support for TypeScript and Python. Add Treesitter for syntax highlighting, nvim-cmp for autocompletion, and Neo-tree for file browsing. Include key mappings for go-to-definition, hover documentation, and code actions.

Real-World Task

Use your Neovim setup to work on a Git Repository for one week. Use LSP features for all navigation, Treesitter for code folding, and nvim-cmp for completions. Note how your editing speed compares to your previous editor. Configure :checkhealth to verify all components work correctly.

Should I switch from Vim to Neovim?

If you want a modern plugin ecosystem, async capabilities, and Lua configuration, yes. If Vim works perfectly for you, there is no urgent need to switch.

Does Neovim support Vimscript?

Yes. Neovim is backward-compatible with Vimscript. You can mix .vim and .lua files in your configuration.

How do I update plugins with Lazy.nvim?

Run :Lazy update in Neovim. Lazy.nvim fetches the latest versions of all registered plugins.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro