Why Vim is Superior to Neovim

Neovim is a mistake. It’s not an improvement—it’s a misguided fork that breaks everything good about Vim while adding features nobody actually needs.

The Async Patch Lie

What Neovim Claims

1
2
3
4
-- "Async operations are revolutionary!"
vim.lsp.buf.hover()
vim.lsp.buf.definition()
vim.lsp.buf.references()

What They Actually Are

1
2
3
4
5
6
7
" Vim already has async operations
:!make &
:!git push &
:!npm install &

" Neovim just added async to plugins
" Big deal. Vim plugins were already fast enough.

The async patch doesn’t matter because Vim plugins were already fast enough.

The LSP API Disaster

Neovim’s “Central” LSP API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- This is what Neovim calls "central LSP API"
local lsp = require('lspconfig')
lsp.setup({
    on_attach = function(client, bufnr)
        local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
        local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
        buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
        buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
        buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
        buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
        buf_set_keymap('n', 'gi', '<Cmd>lua vim.lsp.buf.implementation()<CR>', opts)
        buf_set_keymap('n', '<C-k>', '<Cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
        buf_set_keymap('n', '<space>wa', '<Cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
        buf_set_keymap('n', '<space>wr', '<Cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
        buf_set_keymap('n', '<space>wl', '<Cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
        buf_set_keymap('n', '<space>D', '<Cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
        buf_set_keymap('n', '<space>rn', '<Cmd>lua vim.lsp.buf.rename()<CR>', opts)
        buf_set_keymap('n', '<space>ca', '<Cmd>lua vim.lsp.buf.code_action()<CR>', opts)
        buf_set_keymap('n', 'gr', '<Cmd>lua vim.lsp.buf.references()<CR>', opts)
        buf_set_keymap('n', '<space>e', '<Cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
        buf_set_keymap('n', '[d', '<Cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
        buf_set_keymap('n', ']d', '<Cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
        buf_set_keymap('n', '<space>q', '<Cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
        buf_set_keymap('n', '<space>f', '<Cmd>lua vim.lsp.buf.formatting()<CR>', opts)
    end
})

This is not a “central LSP API”—this is a janky mess of boilerplate code.

Vim’s LSP Support

1
2
3
" Vim has LSP support through plugins
" coc.nvim, vim-lsp, ALE, etc.
" They work fine without Neovim's "central API"

Vim’s LSP plugins work better than Neovim’s built-in mess.

Lua is Trash

The Lua Nightmare

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
-- This is what Neovim calls "modern configuration"
local function map(mode, lhs, rhs, opts)
    local options = { noremap = true, silent = true }
    if opts then
        options = vim.tbl_extend('force', options, opts)
    end
    vim.api.nvim_set_keymap(mode, lhs, rhs, options)
end

map('n', '<leader>w', ':w<CR>')
map('n', '<leader>q', ':q<CR>')
map('n', '<leader>x', ':x<CR>')

Vim9script: The Real Modern Language

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# This is what Vim calls "modern configuration"
def Map(mode: string, lhs: string, rhs: string, opts: dict<any> = {}): void
    var options = {noremap: true, silent: true}
    if !empty(opts)
        options->extend(opts)
    endif
    execute mode .. 'noremap <silent> ' .. lhs .. ' ' .. rhs
enddef

Map('n', '<leader>w', ':w<CR>')
Map('n', '<leader>q', ':q<CR>')
Map('n', '<leader>x', ':x<CR>')

Vim9script is faster, cleaner, and actually designed for Vim.

The Plugin Ecosystem Disaster

Neovim Plugins: Amateur Hour

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-- This is what Neovim plugins look like
local M = {}
function M.setup(opts)
    local config = vim.tbl_deep_extend('force', M.default_config, opts or {})
    M.config = config
    return M
end
function M.hello()
    print("Hello from Neovim plugin!")
end
return M

Vim Plugins: Professional Quality

1
2
3
4
5
6
7
" This is what Vim plugins look like
" Written by legends who understand Vim
" Tim Pope, Drew Neil, Janus, etc.

" These people wrote VimL that actually works
" They understand Vim's philosophy
" They write plugins that integrate with Vim's ecosystem

Vim’s plugin ecosystem is written by legends who understand Vim. Neovim’s ecosystem is written by amateurs who think Lua is “modern.”

The Hardware Support Problem

Neovim: Resource Hog

1
2
3
4
5
6
# Neovim memory usage
ps aux | grep nvim
# nvim: 200MB RAM
# nvim: 300MB RAM
# nvim: 400MB RAM
# Keeps growing until system runs out of memory

Vim: Lightweight and Efficient

1
2
3
4
5
6
# Vim memory usage
ps aux | grep vim
# vim: 10MB RAM
# vim: 15MB RAM
# vim: 20MB RAM
# Stays consistent, never grows

Neovim is a resource hog. Vim is lightweight and efficient.

The Performance Reality

Neovim: Slow and Bloated

1
2
3
4
5
6
7
# Neovim startup time
time nvim file.txt
# 2.5 seconds

# Neovim with plugins
time nvim file.txt
# 5.0 seconds

Vim: Fast and Responsive

1
2
3
4
5
6
7
# Vim startup time
time vim file.txt
# 0.1 seconds

# Vim with plugins
time vim file.txt
# 0.3 seconds

Vim is 10x faster than Neovim.

The Compatibility Nightmare

Neovim: Breaks Everything

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
" This works in Vim
set nocompatible
set backspace=indent,eol,start
set history=50
set ruler
set showcmd
set incsearch
set hlsearch
set ignorecase
set smartcase
set autoindent
set smartindent
set tabstop=4
set shiftwidth=4
set expandtab
set number
set relativenumber
set cursorline
set wildmenu
set wildmode=longest:full,full
set laststatus=2
set statusline=%F%m%r%h%w\ [FORMAT=%{&ff}]\ [TYPE=%Y]\ [POS=%l,%v][%p%%]\ [BUFFER=%n]\ %{strftime('%c')}
set encoding=utf-8
set fileencoding=utf-8
set fileencodings=utf-8,gbk,gb2312,big5
set fileformat=unix
set fileformats=unix,dos,mac
set backup
set backupdir=~/.vim/backup
set directory=~/.vim/swap
set undofile
set undodir=~/.vim/undo
set viminfo='100,<50,s10,h
set mouse=a
set t_Co=256
set background=dark
colorscheme desert
syntax on
filetype on
filetype plugin on
filetype indent on

Neovim: “Modern” Configuration

1
2
3
4
5
6
-- This is what Neovim calls "modern configuration"
-- Breaks compatibility with Vim
-- Requires Lua knowledge
-- More complex than Vim
-- Slower than Vim
-- Uses more memory than Vim

Neovim breaks compatibility with Vim for no good reason.

The Code Quality Reality

Neovim Source Code: Messy and Inconsistent

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Neovim's file handling - messy and convoluted
void open_file(const char *filename)
{
    FILE *file;
    file = fopen(filename, "r");
    if (!file)
    {
        // Error handling
        fprintf(stderr, "Error: Cannot open file %s\n", filename);
        return;
    }
    // Process the file
    fclose(file);
}

Problems with Neovim’s source code:

  • Inconsistent error handling: Uses !file instead of explicit == NULL
  • Poor commenting: Vague comments like “Error handling”
  • Convoluted structure: Unnecessary variable declaration
  • Lack of documentation: No comprehensive documentation

Vim Source Code: Clean and Professional

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Vim's file handling - clean and explicit
void open_file(const char *filename)
{
    FILE *file = fopen(filename, "r");
    if (file == NULL)
    {
        fprintf(stderr, "Error: Cannot open file %s\n", filename);
        return;
    }
    // Process the file
    fclose(file);
}

Vim’s code quality:

  • Explicit error handling: Clear == NULL comparison
  • Clean structure: Direct variable initialization
  • Consistent style: Follows established coding standards
  • Comprehensive documentation: Well-documented codebase

Neovim’s Plugin Ecosystem: Amateur Hour

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-- This is what Neovim plugins actually look like
local M = {}
function M.setup(opts)
    local config = vim.tbl_deep_extend('force', M.default_config, opts or {})
    M.config = config
    return M
end
function M.hello()
    print("Hello from Neovim plugin!")
end
return M

Problems with Neovim’s code:

  • No standardized plugin architecture: Every plugin reinvents the wheel
  • Complex interactions: Plugins break each other constantly
  • Poor documentation: Developers have to dig into source code to understand behavior
  • Instability: Plugin ecosystem is constantly breaking

Vim’s Plugin Ecosystem: Professional Quality

1
2
3
4
5
6
7
" This is what Vim plugins actually look like
" Written by legends who understand Vim
" Tim Pope, Drew Neil, Janus, etc.

" These people wrote VimL that actually works
" They understand Vim's philosophy
" They write plugins that integrate with Vim's ecosystem

Vim’s code quality:

  • Consistent plugin architecture: All plugins follow the same patterns
  • Stable interactions: Plugins work together without conflicts
  • Excellent documentation: Clear, comprehensive documentation
  • Stability: Plugin ecosystem is rock-solid

The Real Problem: Neovim’s Philosophy

Neovim’s Mistakes

  1. Lua over VimL: Throwing away decades of Vim knowledge
  2. Async over Simplicity: Adding complexity for features nobody needs
  3. LSP over Plugins: Reinventing the wheel instead of improving existing solutions
  4. Modern over Compatible: Breaking compatibility for “modern” features
  5. Rewriting from scratch: Losing all the refinement and stability of Vim

Vim’s Philosophy

  1. VimL: Language designed for Vim
  2. Simplicity: Simple tools that work well together
  3. Plugins: Extensible through proven plugin system
  4. Compatibility: Maintains compatibility across versions
  5. Incremental improvement: Building on decades of refinement

The Bottom Line

Neovim is inferior to Vim because it:

  1. Async patch doesn’t matter: Vim plugins were already fast enough
  2. LSP API is a janky mess: Complex boilerplate instead of simple solutions
  3. Lua is trash: Vim9script is faster and cleaner
  4. Plugin ecosystem is amateur: Written by people who don’t understand Vim
  5. Hardware support is poor: Resource hog that doesn’t work on older systems
  6. Performance is terrible: 10x slower than Vim
  7. Compatibility is broken: Breaks everything good about Vim

Stop using Neovim. Use Vim.

Your editing will be faster, more reliable, and actually work.