惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy International News Feed
爱范儿
爱范儿
H
Help Net Security
博客园 - 三生石上(FineUI控件)
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
博客园 - 叶小钗
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
T
Tenable Blog
Project Zero
Project Zero
腾讯CDC
Spread Privacy
Spread Privacy
V
Vulnerabilities – Threatpost
T
Threatpost
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Latest news
Latest news
L
Lohrmann on Cybersecurity
B
Blog RSS Feed
小众软件
小众软件
G
Google Developers Blog
T
Tor Project blog
P
Palo Alto Networks Blog
The Cloudflare Blog
Scott Helme
Scott Helme
D
Darknet – Hacking Tools, Hacker News & Cyber Security
A
Arctic Wolf
博客园 - 聂微东
AWS News Blog
AWS News Blog
L
LINUX DO - 热门话题
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Docker
博客园 - Franky
Know Your Adversary
Know Your Adversary
人人都是产品经理
人人都是产品经理
博客园 - 【当耐特】
P
Privacy & Cybersecurity Law Blog
A
About on SuperTechFans
Cisco Talos Blog
Cisco Talos Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
C
Cisco Blogs
P
Proofpoint News Feed
雷峰网
雷峰网
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog
Security Latest
Security Latest
C
Cybersecurity and Infrastructure Security Agency CISA
Jina AI
Jina AI
Y
Y Combinator Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Why I Built nvim-starter — a Neovim Config Beginners Can Actually Understand
Marius van Zundert · 2026-06-25 · via DEV Community

Kickstart.nvim gives you a working IDE. It also gives you lazy.nvim, nvim-cmp, telescope, nvim-treesitter, and a dozen concepts to learn before you've written a single line of config. I wanted something simpler.


The problem with kickstart.nvim

Let me be clear: kickstart.nvim is a good project. It's the standard recommendation for Neovim beginners, it's maintained by a core Neovim developer, and it ships a genuinely capable setup. I recommend it to people all the time.

But every time I did, I'd watch them hit the same wall. They'd clone the repo, launch Neovim, see plugins install, and then freeze. Not because the config didn't work — because they couldn't read it.

Here's what a beginner sees when they open kickstart.nvim's init.lua:

First, a large require('lazy').setup({...}) block with a DSL they've never seen before — event, cmd, keys, dependencies, opts, config. Before they've learned what vim.opt does, they're staring at lazy-loading triggers and event-driven plugin activation. Then nvim-cmp, which requires four separate source plugins (cmp-nvim-lsp, cmp-buffer, cmp-path, cmp_luasnip) and a configuration block that maps twenty keybindings, defines a formatting function, and wires up capabilities. Then telescope with its own setup and extension loading. Then nvim-treesitter with ensure_installed. Then mason-lspconfig with a manual ensure_installed list.

None of this is wrong — it's just a lot. It's a production config dressed as a starter. The very things that make kickstart powerful (lazy-loading, modular plugin specs, extensible completion sources) are the things that make it illegible to someone who doesn't yet know what a plugin is.

So I built nvim-starter. The goal: a configuration you can read top to bottom in ten minutes and walk away understanding.


What nvim-starter does differently

1. No plugin manager

This is the biggest decision I made, and the one that shapes everything else.

Kickstart.nvim uses lazy.nvim. lazy.nvim is excellent software — Folke is a brilliant developer, and lazy.nvim rightfully became the standard. But it's an abstraction layer between you and your plugins. To understand the config, you first have to understand lazy.nvim's spec format: what event = "VeryLazy" means, how cmd triggers work, why some plugins use dependencies and others don't, what the opts shorthand expands to.

For a beginner, this is backwards. They should be learning Neovim's concepts — buffers, windows, keymaps, options, LSP — not a plugin manager's DSL.

nvim-starter uses vim.pack.add(), which shipped with Neovim 0.12. You give it a list of GitHub URLs:

vim.pack.add({
  { src = "https://github.com/folke/tokyonight.nvim", name = "tokyonight.nvim" },
  { src = "https://github.com/folke/which-key.nvim",   name = "which-key.nvim" },
  { src = "https://github.com/folke/snacks.nvim",       name = "snacks.nvim" },
  -- ...
}, { confirm = false })

That's it. There is nothing to learn. Neovim clones these repos into its standard plugin directory, adds them to the runtimepath, and loads them the same way it's loaded plugins for decades. The "plugin manager" is the editor itself. When a beginner reads this block, they see exactly what's happening: here are the plugins, here are their URLs, they get installed automatically.

No lazy-loading. No event triggers. No after/ directories. Ten plugins load at startup, and with vim.loader.enable() (bytecode caching introduced in Neovim 0.12), startup time is imperceptible. For a starter config with ten plugins, the complexity of lazy-loading isn't worth the cognitive cost.

2. blink.cmp instead of nvim-cmp

When kickstart.nvim was created, nvim-cmp was the only viable completion engine. It works, but it's a sprawling setup. You need:

  • nvim-cmp itself
  • cmp-nvim-lsp for LSP completions
  • cmp-buffer for buffer words
  • cmp-path for filesystem paths
  • cmp_luasnip for snippets
  • A capabilities bridge to wire it into the LSP client
  • A formatting function if you want pretty icons

That's five plugins and a configuration block that typically runs 40–60 lines.

blink.cmp — Saghen's Rust-based completion engine — bundles LSP, path, buffer, and snippet sources internally. The entire completion configuration in nvim-starter is 25 lines:

require("blink.cmp").setup({
  keymap = { preset = "none", ... },
  sources = { default = { "lsp", "path", "snippets", "buffer" } },
  snippets = { preset = "luasnip" },
})

No separate source plugins. No capability bridging (one wildcard LSP config covers it). No formatting function. It's faster at runtime and dramatically simpler to read.

blink.cmp is younger than nvim-cmp and has a smaller ecosystem, but for the four sources a starter config needs — LSP, path, snippets, buffer — it's the simpler tool. I'll take simpler over battle-tested for something meant to be read and understood before it's used.

3. snacks.nvim over telescope (and toggleterm, and neo-tree)

telescope.nvim is a fantastic fuzzy finder. But it's only a fuzzy finder. If you also want a built-in terminal, you install toggleterm.nvim. A file explorer? neo-tree.nvim or nvim-tree.lua. Each of these has its own configuration syntax, its own keybindings, its own documentation to read.

Folke's snacks.nvim bundles all three — picker, terminal, explorer — into one plugin with one setup call. In nvim-starter, the entire UI layer is 10 lines:

require("snacks").setup({
  explorer = { enabled = true },
  terminal = { enabled = true },
  picker = { matcher = { fuzzy = true, smartcase = true, filename_bonus = true } },
})

One plugin to understand instead of three. One set of keybindings to learn. One repo to trust. For a beginner who hasn't yet internalized the difference between a picker, a terminal buffer, and a file tree, this collapsing of concepts is a genuine learning aid.

4. No nvim-treesitter — just what Neovim ships

nvim-treesitter is another plugin that's excellent software and adds unnecessary complexity for beginners. It manages parser installations through :TSInstall, which means you're learning a plugin-specific command before you've learned :help. It has its own configuration syntax (ensure_installed, highlight = { enable = true }). It periodically prompts you about parser updates.

Neovim 0.12 ships with built-in Treesitter support and includes parsers for C, Lua, Markdown, Vimscript, vimdoc, and Query. That covers the languages most new Neovim users encounter first: Lua for their config, Markdown for notes, and maybe C if they're systems-curious.

For additional languages, you install parsers through your OS package manager:

$ apt install tree-sitter-python
$ apt install tree-sitter-rust

Or via the tree-sitter CLI:

$ tree-sitter install python

No Neovim plugin involved. No :TSInstall. The FileType autocmd in nvim-starter silently skips languages without parsers using pcall — no errors, no prompts, no confusion. When a beginner eventually installs a parser, highlighting just works.

This is a deliberate philosophical choice: parser management belongs to the OS, not to your editor's plugin system.

5. Zero per-server LSP configuration

In most Neovim configs — including kickstart — every language server needs its own setup block:

lspconfig.pyright.setup({ ... })
lspconfig.rust_analyzer.setup({ ... })
lspconfig.lua_ls.setup({ ... })

Multiply this by however many languages you use, add capability merging and on_attach callbacks, and the LSP section alone can hit a hundred lines.

nvim-starter takes a different approach. mason-lspconfig's automatic_enable = true means: if a server binary exists on disk (because the user installed it through Mason's UI), start it automatically. No per-server blocks. No boilerplate.

Capabilities for blink.cmp are merged once, globally:

vim.lsp.config("*", {
  capabilities = require("blink.cmp").get_lsp_capabilities(...),
})

One line. Every server, present and future, gets completion, signature help, and snippet capabilities. When I install pyright in Mason, it works. When I install rust_analyzer, it works. There is nothing to write, nothing to maintain, nothing to explain.

For beginners, this transforms the LSP experience from "read the lspconfig docs for your language" to "open Mason, press i on the server you want, restart neovim." That's the level of friction I wanted.

6. Single-file, by design

Kickstart.nvim starts as a single file but encourages modularization — its README suggests splitting into lua/plugins/, lua/opts/, lua/keymaps/. This is good practice for a growing config, but it's also the moment a beginner's understanding fragments. Suddenly the colorscheme is in one file, keymaps in another, and LSP config in a third, connected through require() calls that assume you understand Lua's module system.

nvim-starter's CONTRIBUTING.md states it plainly:

Stay single-file. The whole point is a single init.lua with comments.

The entire config is 363 lines, organized into 16 numbered sections. It starts with a comment block telling you the three most common tweaks (colorscheme, indent size, plugin list) and their line numbers. Section 0 enables the loader. Section 1 sets the leader key. Section 2 declares plugins. And so on, linearly, until section 16 enables Treesitter.

You read it top to bottom. You understand it. Then you fork it, rename it, and build your own. nvim-starter isn't a framework you extend — it's a reference implementation you learn from and outgrow.


Why I chose these specific plugins

Every plugin in nvim-starter passed a simple test: is this essential for a beginner, and is it the simplest implementation of what it does?

Plugin Why this one
tokyonight.nvim Dark theme, well-maintained, widely used. Gruvbox is commented-out as an alternative on the very next line.
which-key.nvim Shows available keybindings when you pause on <Space>. Beginners don't memorize keymaps — they discover them.
snacks.nvim One plugin replaces three (fuzzy finder, terminal, explorer). Less to install, less to configure, less to read.
mason.nvim + mason-lspconfig.nvim GUI server installer + auto-wiring. Beginners shouldn't need to know where binaries live or how cmd tables work.
nvim-lspconfig The standard LSP configuration library. Still needed for server-specific defaults, even with automatic_enable.
blink.cmp + blink.lib Rust-based completion that bundles its sources. Faster and simpler than nvim-cmp's source-plugin ecosystem.
gitsigns.nvim Git gutter markers. Beginners use Git. Seeing what changed is immediately useful.
guess-indent.nvim Auto-detects indentation per file. Beginners open files from projects they didn't create — this saves them from mixing tabs and spaces.
LuaSnip Snippet expansion. Powers the snippet source in blink.cmp. The only plugin with a build hook (compiles its regex engine on install).

That's 10 plugins, 11 if you count blink.lib (a dependency of blink.cmp). No file tree, no statusline plugin, no debug adapter, no auto-formatter beyond LSP formatting. Each omission is documented in docs/plugins.md with recommendations if you want to add them later.


What nvim-starter doesn't try to be

It's not your forever-config. It's deliberately undersized. Once you're comfortable with Neovim, you'll want things it doesn't include — a statusline, a debug adapter, auto-formatting on save, session management. That's by design. nvim-starter gets you to the point where you know what you want to add, which is the real goal.

It's not modular. There are no lua/ subdirectories, no require() chains, no plugin specs split across files. This is a constraint, not an oversight. Modularity is the right call for a configuration you'll maintain for years — but it's the wrong call for a configuration meant to be read in one sitting.

It's not version-agnostic. nvim-starter requires Neovim ≥ 0.12. This is a hard requirement and I'm comfortable with it. vim.pack.add() and native Treesitter are the right primitives for a beginner config, and they didn't exist before 0.12. Ubuntu 24.04 LTS ships Neovim 0.9.5, so you'll need a PPA, AppImage, or manual build. I think the trade-off — a simpler config that leverages editor-native features — is worth the install step. If Neovim 0.12 isn't available to you, use kickstart.nvim instead.


What you get in five minutes

Install it:

curl -fsSL https://raw.githubusercontent.com/Mvzundert/nvim-starter/main/install.sh | bash

Open a file. Plugins clone for ~30 seconds. Then:

You get Press
Keybinding cheat sheet <Space> and wait
Fuzzy file finder <Space>sf
Content search (grep) <Space>sg
LSP server installer (GUI) <Space>cm
Terminal toggle <Space>tt
File explorer <Space>e
Go-to-definition gd (with LSP attached)
Hover docs K
Rename symbol <Space>rn
Code actions <Space>ca
Auto-completion Just type
Format buffer <Space>f

Install a language server by opening Mason (<Space>cm), pressing 2 for LSP servers, searching for your language, and pressing i. Reopen your file. Autocompletion, go-to-definition, and diagnostics all work. No config written. No docs read. Just a working IDE.


The trade-offs I'm comfortable with

Every design decision is a trade-off. Here are the ones I made and why I stand by them:

Neovim ≥ 0.12 only. Yes, this excludes stable-distribution users. But vim.pack.add() eliminates the plugin manager abstraction entirely. That single simplification justifies the version requirement. Beginners installing Neovim fresh aren't tied to a distro package anyway — they're following a "how to install Neovim" tutorial that gives them the latest version.

No lazy-loading. Ten plugins load at startup. On any machine built in the last decade, with vim.loader.enable() caching bytecode, this is under 50 milliseconds. The cognitive cost of explaining lazy-loading to a beginner vastly outweighs the performance gain.

blink.cmp instead of nvim-cmp. blink.cmp is newer and has a smaller plugin ecosystem. But a beginner doesn't need custom completion sources — they need LSP completions, buffer words, and file paths. blink.cmp does all three out of the box with a 25-line config. If they eventually need a source blink.cmp doesn't support, they'll have learned enough to evaluate nvim-cmp themselves.

No :LspInfo. Neovim 0.12 replaced :LspInfo with :checkhealth vim.lsp. This is documented in the README and in the inline comments, but I know it will trip up users following older tutorials. It's a Neovim upstream decision I can't control, and I think documenting it clearly is sufficient.

Built-in Treesitter requires extra steps for more languages. If you work in Python, Rust, Go, TypeScript, Bash, and ten other languages, installing parsers through your package manager is an extra step per language. nvim-treesitter's :TSInstall all is genuinely more convenient for polyglots. But nvim-starter is for beginners — beginners typically work in one or two languages. Installing one or two tree-sitter packages isn't a meaningful burden, and avoiding nvim-treesitter keeps the plugin count down and the mental model simple.


Why you might choose nvim-starter over kickstart.nvim

Use nvim-starter if:

  • You're new to Neovim and want to understand your config. Kickstart works, but it's hard to read. nvim-starter is 363 lines of commented Lua that tells you exactly what every line does and why it's there.
  • You don't want to learn a plugin manager before learning Neovim. lazy.nvim is powerful, but it's an abstraction. nvim-starter uses vim.pack.add() — there is no plugin manager to learn because the editor is the plugin manager.
  • You want to get productive in five minutes, not five hours. Install, launch, install one LSP server, start coding. That's the workflow. There's no config to write.
  • You learn by reading working code. nvim-starter is a reference implementation. Read it top to bottom. Then delete it and write your own — you'll know enough.
  • You prefer smaller dependency trees. Fewer plugins, fewer repositories to trust, fewer version interactions to debug.

Stick with kickstart.nvim if:

  • You need Neovim ≥ 0.9 compatibility (Ubuntu LTS, Debian stable, RHEL).
  • You want lazy-loading and fine-grained startup control.
  • You want nvim-cmp's mature plugin ecosystem.
  • You want :TSInstall convenience for dozens of languages.
  • You want a config you can grow modularly without rewriting from scratch.

The bottom line

I built nvim-starter because I believe the first Neovim configuration a beginner sees should be legible. They should be able to read it in one sitting, understand what every section does, and feel confident tweaking it. The plugins should auto-install without a plugin manager. The LSP should auto-wire without per-server configuration. The code should document itself.

Kickstart.nvim is a launchpad. nvim-starter is a tutorial that happens to give you a working IDE.


Repository: github.com/Mvzundert/nvim-starter

Requirements: Neovim ≥ 0.12, Git, Nerd Font (optional)

License: MIT