My Neovim Setup for Python, Go, and TypeScript

Abstract generated cover for My Neovim Setup for Python, Go, and TypeScript.

I like Neovim because it can be very fast without feeling bare. The goal is not to turn the editor into a full IDE clone. The goal is to build a focused editing environment that handles the boring parts well:

  • finding files
  • jumping around code
  • running formatters
  • using language servers
  • searching the project
  • working inside a terminal-heavy workflow For Python, Go, and TypeScript, the setup does not need to be complicated. It needs a few reliable pieces that work every day.

The Mental Model

My mental model for Neovim is simple:

Neovim should be the place where editing, navigation, and feedback happen quickly. It does not need to own everything. I still use the terminal directly for many commands. I still run test suites from the command line. I still inspect docs in a browser. The editor does not need to hide those tools. The setup should make common actions cheap:

  • open a file by fuzzy search
  • jump to a definition
  • rename a symbol
  • format a buffer
  • search for text with ripgrep
  • see diagnostics without leaving the file
  • run a terminal command when needed That is the core.

Plugin Manager

Most modern Neovim setups use a plugin manager. `lazy.nvim` is a common choice because it keeps plugin configuration organized and can load plugins only when needed. The exact plugin manager matters less than the structure: ```plain text nvim/ init.lua lua/ config/ plugins/

I prefer having plugin configuration split by purpose instead of putting everything into one huge file.
Example categories:
```plain text
plugins/editor.lua
plugins/lsp.lua
plugins/completion.lua
plugins/git.lua
plugins/search.lua
plugins/theme.lua

This makes the setup easier to change later.

File Search and Project Search

The two navigation tools I care about most are file search and text search. For file search, a fuzzy finder is essential. Many setups use Telescope or fzf-lua. The workflow is: ```plain text leader + f -> find file leader + g -> live grep leader + b -> open buffer

The exact keybindings are personal, but they should be memorable.
For text search, I want the editor to use \`rg\` under the hood. Ripgrep is fast, respects \`.gitignore\`, and works well across large projects.
This matters a lot in real projects. If finding a file or searching for a function name feels slow, the whole editor feels slow.
## Language Servers
Language servers are what make modern Neovim practical for application work.
They provide:
- diagnostics
- go to definition
- hover information
- rename symbol
- references
- completion
- code actions
For the languages I use often:
```markdown
| Language | Common language server |
| --- | --- |
| Python | `pyright` or `basedpyright` |
| Go | `gopls` |
| TypeScript | `typescript-language-server` |

The important part is making sure each language server is installed and wired into Neovim's LSP client. Once that is working, the editor starts to feel much more useful without needing a heavyweight setup.

Formatting

Formatting should be boring. For Python, I usually want something like `ruff` or `black`. For Go, `gofmt` is the standard. For TypeScript, Prettier is common. The editor should be able to format the current file with one keybinding: ```plain text leader + format

Some people like format-on-save. I usually like it when the project is already consistent. On messy projects, I prefer manual formatting so I do not accidentally create huge diffs.
That choice depends on the repository.
## Completion
Completion should help without getting in the way.
The usual pieces are:
- LSP completion
- buffer words
- file paths
- snippets if the project benefits from them
I do not want completion to be noisy. If the completion menu constantly suggests irrelevant things, it slows me down instead of helping.
This is especially noticeable in TypeScript projects where there can be many exported symbols. Good completion is useful. Bad completion is clutter.
## Git Integration
I like having lightweight Git feedback in the editor:
- changed lines in the gutter
- quick blame for the current line
- stage or reset small hunks when useful
But I still prefer the terminal for most Git work.
That keeps the workflow simple:
```bash
git status
git add path/to/file
git commit -m "message"
git push

Neovim should make Git status visible, not replace understanding Git.

Common Mistakes

Mistake 1: Installing too many plugins at once

It is easy to copy a large config and end up with a setup you do not understand. Start with editing, search, LSP, formatting, and Git indicators. Add more only when you feel a real problem.

Mistake 2: Ignoring project tools

Neovim should respect the project. If the project uses Ruff, use Ruff. If the project uses Prettier, use Prettier. If the project has a specific TypeScript config, let the language server read it. The editor should not fight the repository.

Mistake 3: Making keybindings impossible to remember

Keybindings should have a pattern. For example: plain text leader + f = file actions leader + g = grep or git actions leader + l = language actions The exact choices are less important than consistency.

Where This Shows Up in Real Projects

A good Neovim setup helps most when switching between different kinds of projects. In a Django project, I want to jump between models, views, templates, and tests quickly. In a Go project, I want `gopls` and `gofmt` to be invisible and reliable. In a TypeScript project, I want imports, types, and file navigation to feel smooth. The setup is not about showing off an editor. It is about removing friction from ordinary development work.

Key Takeaways

  • Start with navigation, LSP, formatting, search, and Git feedback.
  • Let project tools drive formatting and diagnostics.
  • Keep the config understandable enough that you can fix it later.
  • Neovim works best when it complements the terminal instead of trying to replace it.

    Related Articles

  • Setting Up a Mac for Development

  • Terminal Tools I Actually Use
  • Git Branching Explained: Feature Branch to Master

← Back to Blog Index