Getting LazyVim set up for senior-level Go development is less about piling on dozens of random plugins and more about orchestrating the "Big Three": LSP (gopls), Linting (golangci-lint), and Debugging (delve).
This guide transforms a stock LazyVim installation into a production-ready Go IDE.
Before touching Neovim, ensure the industry-standard binaries are on your $PATH:
# Install Delve for debugging and Golangci-lint for senior-level linting
go install github.com/go-delve/delve/cmd/dlv@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Install gofumpt for stricter formatting (optional but recommended)
go install mvdan.cc/gofumpt@latest
LazyVim has a pre-configured Go module. This handles gopls, nvim-dap-go, and neotest-go automatically.
- Open Neovim:
nvim - Type
:LazyExtras - Find
lang.goand pressxto enable it. - Restart Neovim.
For a "Senior" setup, we need more than defaults. Create a new file at ~/.config/nvim/lua/plugins/go.lua and paste the following. This adds gomodifytags (for JSON tags) and impl (for implementing interfaces).
return {
-- Core LSP & Tooling Configuration
{
"neovim/nvim-lspconfig",
opts = {
servers = {
gopls = {
settings = {
gopls = {
gofumpt = true,
codelenses = {
gc_details = false,
generate = true,
regenerate_cgo = true,
run_govulncheck = true,
test = true,
tidy = true,
upgrade_dependency = true,
vendor = true,
},
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
analyses = {
fieldalignment = true,
nilness = true,
unusedparams = true,
unusedwrite = true,
useany = true,
},
usePlaceholders = true,
completeUnimported = true,
staticcheck = true,
directoryFilters = { "-.git", "-.vscode", "-.idea", "-.vscode-test", "-node_modules" },
semanticTokens = true,
},
},
},
},
setup = {
gopls = function(_, opts)
-- workaround for gopls not supporting semanticTokensProvider
-- https://github.com/golang/go/issues/54531#issuecomment-1464982242
LazyVim.lsp.on_attach(function(client, _)
if client.name == "gopls" then
if not client.server_capabilities.semanticTokensProvider then
local semantic = client.config.capabilities.textDocument.semanticTokens
client.server_capabilities.semanticTokensProvider = {
full = true,
legend = {
tokenTypes = semantic.tokenTypes,
tokenModifiers = semantic.tokenModifiers,
},
range = true,
}
end
end
end)
end,
},
},
},
-- Add specific Go tools to Mason
{
"williamboman/mason.nvim",
opts = {
ensure_installed = {
"goimports",
"gofumpt",
"gomodifytags",
"impl",
"delve",
},
},
},
}
Add these to ~/.config/nvim/lua/config/keymaps.lua to speed up common tasks like adding JSON tags or generating interface stubs.
local map = vim.keymap.set
-- Go specific mappings
map("n", "<leader>gsj", "<cmd>GoTagAdd json<cr>", { desc = "Add JSON struct tags" })
map("n", "<leader>gsy", "<cmd>GoTagAdd yaml<cr>", { desc = "Add YAML struct tags" })
map("n", "<leader>gie", "<cmd>GoIfErr<cr>", { desc = "Generate if err != nil" })
Don't just trust the config; verify the pipeline.
- Create a
main.go. - Write a messy function and save. It should auto-format via
gofumptand organize imports viagoimports. - Check for Inlay Hints (e.g., parameter names showing up in gray text).
- Set a breakpoint on a line using
<leader>db. - Start the debugger with
<leader>dc. - Requirement: Ensure you have a
go.modfile in the directory, or Delve will be cranky.
- Open a
_test.gofile. - Hover over a test function and press
<leader>tr(Test Run). - Press
<leader>tsto see the summary panel on the right.
Since you're on a fresh install, run :checkhealth frequently in the first hour. It will tell you exactly which binary (like gopls or dlv) Neovim is failing to find.
Would you like me to provide a snippet to configure golangci-lint to run automatically on every save?