chore: added blog post draft b9498a9a
Steve · 2026-03-15 23:53 8 file(s) · +328 −0
packages/client/public/blog-images/other/buffers.mp4 (added) +0 −0

Binary file — no preview.

packages/client/public/blog-images/other/mini-completion.mp4 (added) +0 −0

Binary file — no preview.

packages/client/public/blog-images/other/mini-files.mp4 (added) +0 −0

Binary file — no preview.

packages/client/public/blog-images/other/mini-pick-files.mp4 (added) +0 −0

Binary file — no preview.

packages/client/public/blog-images/other/nvim-diagnostics-icons.png (added) +0 −0

Binary file — no preview.

packages/client/public/blog-images/other/nvim-diagnostics.mp4 (added) +0 −0

Binary file — no preview.

packages/client/public/blog-images/other/nvim-find.mp4 (added) +0 −0

Binary file — no preview.

packages/client/src/content/post/returning-to-neovim.mdx (added) +328 −0
1 +
---
2 +
title: "Returning to Neovim"
3 +
publishDate: "14 Mar 2026"
4 +
description: "Once again coming back to the editor I can't shake"
5 +
tags: []
6 +
ogImage: ""
7 +
---
8 +
9 +
// Cover
10 +
11 +
One of my more popular blog posts was how and why I switched to [Zed from Neovim](https://stevedylan.dev/posts/leaving-neovim-for-zed/). That was almost two years ago, and in that period Zed was my daily driver for programming. Every now and then I would still use Neovim to edit a config or make a quick edit, but outside of that, Zed was where I lived. Since then the Zed team has naturally had to keep up with all the AI hype. Thankfully most of the editing experience has remained in-tact, and with the right settings you may not even notice it's there. However there certainly have been instances where Zed felt buggy, and not as lean as it used to be. 
12 +
13 +
## What Happened
14 +
15 +
The real shift happened about a week ago when Zed updated its terms and policies. It was at this time when the dev community realized that there was a new age restriction of 18+. The Zed team clarified that this was in regards to their online services and platform used for AI assisted coding, but it was still a bit unnerving. A few people had already made forks of Zed through the open source licenses that the editor is under, and I did try them, but it was clear that the Zed experience was not the same. Some stuff didn't work, extensions had to be installed manually, just overall proved to be something else entirely.
16 +
17 +
That was the wake up call. I realized I couldn't really trust Zed moving forward, not while its under the control of a VC backed company. I really think the team is awesome and what they're building is perhaps the best editor alternative to VSCode, but I also understood that they have to make money somehow. When it comes to writing code, that is the last place I want to be stuck in. I have to be able to write code productively without my flow being interrupted by the decisions of higher managemnet. Neovim isn't a perfect drop in replacement in this regard either, but I trust it way more as a community backed and managed project. 
18 +
19 +
Since switching back to Neovim full time, I've honestly had no regrets. I updated my config last year, and having the opportunity to daily drive it has proven how capable it truly is. There was a mental plan to adjust pieces to meet what I might have missed in Zed, but I haven't had to make any changes yet. Naturally, since I'm back on Neovim, I gotta go over the config.
20 +
21 +
## The Config
22 +
23 +
There's generally two ways people end up configuring Neovim. One path is using a distro like [LazyVim](https://www.lazyvim.org/), the other is writing it from scratch. I've taken the distro path before and I think it's great if you have no idea what you want, but eventually you might find yourself wanting to slim things down. If doing a config from scratch feels intimidating, I would highly recommend [this series](https://www.youtube.com/playlist?list=PLsz00TDipIffreIaUNk64KxTIkQaGguqn) which goes over all the different aspects of a config. Below is a quick overview of my config structure:
24 +
25 +
```
26 +
nvim
27 +
└── lazy-lock.json
28 +
└── lua
29 +
    └── plugins
30 +
        └── ai-vim.lua
31 +
        └── treesitter.lua
32 +
        └── mini.lua
33 +
        └── tmux-navigator.lua
34 +
        └── colorschemes.lua
35 +
    └── config
36 +
        └── options.lua
37 +
        └── keymaps.lua
38 +
        └── autocmds.lua
39 +
    └── core
40 +
        └── lazy.lua
41 +
        └── lsp.lua
42 +
└── lsp
43 +
    └── gopls.lua
44 +
    └── solc.lua
45 +
    └── asm-lsp.lua
46 +
    └── rust-analyzer.lua
47 +
    └── astro.lua
48 +
    └── html.lua
49 +
    └── json.lua
50 +
    └── lua_ls.lua
51 +
    └── tsserver.lua
52 +
└── init.lua
53 +
```
54 +
55 +
I'll do my best to go over all of the different pieces I have here. 
56 +
57 +
### Plugin Manager
58 +
59 +
I've been using [lazy.nvim](https://github.com/folke/lazy.nvim) for years (not to be confused with LazyVim, a distro that uses lazy.nvim), and it's just solid. Always works, zero issues, and boy it can go _fast_ (will go over that later). There's not much else to say due to how much of an industry standard it is. I might give the new native plugin manager coming in Neovim 12, but I've already seen some people say it's not as fast as lazy.nvim, so I'll be keeping an eye on it for future development.
60 +
61 +
### LSP
62 +
63 +
The Language Server Protocol (LSP) provides a standard for different languages to provide feedback in dev workflows. Common example would be writing an incorrect type in Typescript which would cause the compiler to fail. Instead of having to run it, the editor shows some red lines saying something is wrong. Many editors set this up behind the scenes, but that's not the case for Neovim, and it can be one of the big things people struggle with. In the past I've used a few plugin combinations which were always a mess, but I was so excited that native LSP support came to Neovim last year! [This video](https://youtu.be/IZnhl121yo0) does a fantastic job walking you through how to set it all up, but its really as simple as creating a dedicated `lsp` folder with the different languages, then making a `lsp.lua` config file. Here's an example for Rust:
64 +
65 +
```lua
66 +
return {
67 +
	cmd = {
68 +
		"rust-analyzer",
69 +
	},
70 +
	filetypes = {
71 +
		"rust",
72 +
	},
73 +
	root_markers = {
74 +
		"Cargo.toml",
75 +
		"Cargo.lock",
76 +
		".git",
77 +
	},
78 +
	settings = {
79 +
		["rust-analyzer"] = {
80 +
			cargo = {
81 +
				allFeatures = true,
82 +
				loadOutDirsFromCheck = true,
83 +
				runBuildScripts = true,
84 +
			},
85 +
			-- Add other rust-analyzer specific settings here
86 +
			checkOnSave = true,
87 +
			procMacro = {
88 +
				enable = true,
89 +
				ignored = {
90 +
					leptos_macro = {
91 +
						-- "component",
92 +
						"server",
93 +
					},
94 +
				},
95 +
			},
96 +
		},
97 +
	},
98 +
	single_file_support = true,
99 +
	log_level = vim.lsp.protocol.MessageType.Warning,
100 +
}
101 +
```
102 +
103 +
This simply tells Neovim what files to use the rust-analyzer LSP for, what files might indicate a project, and any other options we may want to add. We follow the same structure for all languages or frameworks that have an LSP. Then inside `lsp.lua` we just add the following configuration:
104 +
105 +
```lua
106 +
vim.lsp.enable({
107 +
  "astro",
108 +
  "gopls",
109 +
  "lua_ls",
110 +
  "tsserver",
111 +
  "rust-analyzer",
112 +
  "asm-lsp",
113 +
  "solc",
114 +
  "html",
115 +
  "json"
116 +
})
117 +
118 +
vim.diagnostic.config({
119 +
  virtual_lines = false,
120 +
  -- virtual_text = true,
121 +
  underline = true,
122 +
  update_in_insert = false,
123 +
  severity_sort = true,
124 +
  float = {
125 +
    border = "rounded",
126 +
    source = true,
127 +
  },
128 +
  signs = {
129 +
    text = {
130 +
      [vim.diagnostic.severity.ERROR] = "󰅚 ",
131 +
      [vim.diagnostic.severity.WARN] = "󰀪 ",
132 +
      [vim.diagnostic.severity.INFO] = "󰋽 ",
133 +
      [vim.diagnostic.severity.HINT] = "󰌶 ",
134 +
    },
135 +
    numhl = {
136 +
      [vim.diagnostic.severity.ERROR] = "ErrorMsg",
137 +
      [vim.diagnostic.severity.WARN] = "WarningMsg",
138 +
    },
139 +
  },
140 +
})
141 +
```
142 +
143 +
The key is `vim.lsp.enable()` where we pass in the names of all our files that have configs. Everything else is just some nicer configuration for looking at diagnostics.
144 +
145 +
![nvim diagnostics icons](/blog-images/other/nvim-diagnostics-icons.png) 
146 +
147 +
It's that simple, and I absolutely love how minimal the experience is. Does require understanding what your LSPs are, where they live, and how to run them, but totally worth it. 
148 +
149 +
### Plugins
150 +
151 +
You might have noticed that I don't have that many plugins, but it's actually a bit decieving. 
152 +
153 +
- `ai-vim.lua` - Small inline AI editing plugin which I don't actually use much, will probably cut it.
154 +
- `treesitter.lua` - Syntax highlighting, pretty standard.
155 +
- `tmux-navigator.lua` - Lets me use `ctrl+h/j/k/l` to switch between a Neovim session and another tmux pane.
156 +
- `colorschemes.lua` - Themes baby, currently on my own called [Darkmatter](https://github.com/stevedylandev/darkmatter-nvim)
157 +
The one I didn't list here is [mini.nvim](https://github.com/nvim-mini/mini.nvim), which is the true star of this config. mini.nvim is a collection of minimal plugins that are installed and setup through a single config. They're all simple, functional, and they really helps lighten up your config. Here's a quick run down of some of my favorites.
158 +
159 +
**mini.completion**
160 +
161 +
<video
162 +
  autoPlay
163 +
  muted
164 +
  loop
165 +
  playsinline
166 +
  className="w-full aspect-video"
167 +
  src="/blog-images/other/mini-completion.mp4"
168 +
></video>
169 +
170 +
This would normally be handled through something heavier like coc.nvim, but it's truly awesome to have a simple and lightweight option inside mini.nvim.
171 +
172 +
**mini.files**
173 +
174 +
<video
175 +
  autoPlay
176 +
  muted
177 +
  loop
178 +
  playsinline
179 +
  className="w-full aspect-video"
180 +
  src="/blog-images/other/mini-files.mp4"
181 +
></video>
182 +
183 +
A minimal file explorer thats a fun mix between oil and netrw.
184 +
185 +
**mini.pick**
186 +
187 +
<video
188 +
  autoPlay
189 +
  muted
190 +
  loop
191 +
  playsinline
192 +
  className="w-full aspect-video"
193 +
  src="/blog-images/other/mini-pick-files.mp4"
194 +
></video>
195 +
196 +
Pick anything. Actually though. In a lot of ways this replaces telescope and lets me fuzzy find files, buffers, you name it!
197 +
198 +
### Other Bits
199 +
200 +
There are some smaller quality of life pieces I have that don't really fit into any specific category, so here's a few my favorites.
201 +
202 +
**VimEnter**
203 +
204 +
I got this one from [Adib Hanna](https://www.youtube.com/@adibhanna) a long time ago. Instead of showing a start screen when I open Neovim, instead I use `mini.pick` to fuzzy find all files within the current directory.
205 +
206 +
```lua
207 +
vim.api.nvim_create_autocmd("VimEnter", {
208 +
  callback = function()
209 +
    if vim.fn.argv(0) == "" then
210 +
      vim.defer_fn(function()
211 +
        require("mini.pick").builtin.files()
212 +
      end, 100) -- Wait 100ms
213 +
    end
214 +
  end,
215 +
})
216 +
```
217 +
218 +
**Buffer Management**
219 +
220 +
<video
221 +
  autoPlay
222 +
  muted
223 +
  loop
224 +
  playsinline
225 +
  className="w-full aspect-video"
226 +
  src="/blog-images/other/buffers.mp4"
227 +
></video>
228 +
229 +
I don't have tabs setup in Neovim as I started to realized I don't really need them. I can use my keyboard shortcuts to move between buffers horizontally, 
230 +
231 +
```lua
232 +
-- Navigate buffers
233 +
map("n", "<S-l>", ":bnext<CR>", opts)
234 +
map("n", "<S-h>", ":bprevious<CR>", opts)
235 +
```
236 +
237 +
or filter through them with `mini.pick`: 
238 +
239 +
```lua
240 +
map("n", "<leader>o", "<cmd>Pick buffers<CR>", opts)
241 +
```
242 +
243 +
Then I can just close them with the following keymap:
244 +
245 +
```lua
246 +
map("n", "<leader>c", ":bd<cr>", opts)
247 +
```
248 +
249 +
**Diagnostics**
250 +
251 +
<video
252 +
  autoPlay
253 +
  muted
254 +
  loop
255 +
  playsinline
256 +
  className="w-full aspect-video"
257 +
  src="/blog-images/other/nvim-diagnostics.mp4"
258 +
></video>
259 +
260 +
Nothing too fancy here but it is nice how versatile the experience can be. I can either use this keymap to do a hover diagnostic:
261 +
262 +
```lua
263 +
map("gl", vim.diagnostic.open_float, "Open Diagnostic Float")
264 +
```
265 +
266 +
Or I can view all diagnostics for the project with mini.pick:
267 +
268 +
```lua
269 +
map("n", "<leader>d", "<cmd>Pick diagnostic<CR>", opts)
270 +
```
271 +
272 +
**Finding Stuff**
273 +
274 +
<video
275 +
  autoPlay
276 +
  muted
277 +
  loop
278 +
  playsinline
279 +
  className="w-full aspect-video"
280 +
  src="/blog-images/other/nvim-find.mp4"
281 +
></video>
282 +
283 +
One of the most important things an editor needs is an easy way to find anything, and I'm quite pleased with what I have setup here. To start, if I wanted to search the entire codebase for a given string, I can use mini.pick with `live_grep`. 
284 +
285 +
```lua
286 +
map("n", "<leader>/", "<cmd>Pick grep_live<CR>", opts)
287 +
```
288 +
289 +
Same goes for buffers.
290 +
291 +
```lua
292 +
map("n", "<leader>o", "<cmd>Pick buffers<CR>", opts)
293 +
```
294 +
295 +
For files, I can either do a fuzzy find like so:
296 +
297 +
```lua
298 +
map("n", "<leader>f", "<cmd>Pick files<CR>", opts)
299 +
```
300 +
301 +
Or I can use the file browser with mini.files. 
302 +
303 +
```lua
304 +
map("n", "<leader>e", "<cmd>lua MiniFiles.open()<CR>", opts)
305 +
```
306 +
307 +
308 +
Last but not least, you can also use Pick to get all the help manuals for Neovim or the plugins installed. 
309 +
310 +
```lua
311 +
map("n", "<leader>hh", "<cmd>Pick help<CR>", opts)
312 +
  ```
313 +
314 +
### Speed
315 +
316 +
```
317 +
025.359  000.037: BufEnter autocommands
318 +
025.363  000.004: editing files in windows
319 +
025.381  000.019: --- NVIM STARTED ---
320 +
```
321 +
322 +
This configuration is incredibly fast. Startup times averages around ~25ms. A more detailed report can be found below. 
323 +
324 +
[`.nvim-startup.txt`](https://sipp.stevedylan.dev/s/dJfiLGUx9u)
325 +
326 +
## Wrapping Up
327 +
328 +
I really do appreciate the time I had with Zed and it is a solid editor; I don't fault anyone who uses it. Personally I've just been through this kind of thing too many times, where I thoroughly enjoy and depend on a tool, just for it to go sideways and absolutely cripple my productivity. The Arc Browser was a great example of this. I would much rather jump ship early, figure out a new workflow that is dependable, and stick with it. That's exactly what I've done with Neovim, and it's good to be back.