How to Set Up VS Code for Go Development

Cli
Install the Go extension and configure gopls in VS Code to enable intelligent Go development features.

The silent editor

You open VS Code. You type package main. You hit save. Nothing happens. You make a typo in fmt.Println and expect a red squiggle. The editor stays blank. You assume Go is broken. You think your installation is corrupt. The truth is simpler. VS Code is a text editor. It knows nothing about Go until you install the Go extension and start the language server. Without gopls, you are typing into a void.

Go development relies on a language server protocol. The editor sends keystrokes and file changes to a background process. That process analyzes the code, checks types, resolves imports, and streams results back. If that process isn't running, your editor is just a fancy notepad. The Go extension manages this process, but you need to trigger the setup correctly.

gopls is the engine

The Go extension does not parse Go code. It launches gopls, the official language server from the Go team, and translates your actions into requests. gopls runs as a separate process. It reads your files, builds a dependency graph, checks types, and sends diagnostics to the editor.

If gopls crashes, your editor survives, but your intelligence features vanish. Autocomplete stops. Go-to-definition breaks. Error highlighting disappears. The extension is the interface. gopls is the engine. When things go wrong, the problem is usually the engine, not the interface.

gopls also runs other tools. It can invoke goimports to organize imports on save. It can run staticcheck for deeper analysis. It can trigger go build to verify compilation. The extension coordinates these tools, but gopls is the central hub.

Install and initialize

The fastest path to a working setup starts with the extension and the toolchain. The Go extension requires helper binaries like gopls, goimports, and dlv. These are not included in the Go distribution. The extension downloads them to your GOPATH/bin directory.

Run the installation command and trigger the tool update from the Command Palette.

# Install the official Go extension
code --install-extension golang.go
# Open VS Code and run "Go: Install/Update Tools" from the Command Palette

The extension checks for missing tools and prompts you to install them. Accept the prompt. The tools are downloaded and cached. Future projects reuse the same binaries.

Open your settings and ensure gopls is enabled. Modern versions of the extension enable gopls by default, but explicit configuration prevents confusion.

{
  "go.useLanguageServer": true,
  "gopls": {
    "ui.diagnostic.analyses": {
      "unusedparams": true
    }
  }
}

The go.useLanguageServer flag is legacy but harmless. The gopls object configures the language server directly. The unusedparams analysis highlights function parameters that are never used, which helps catch dead code early.

Convention aside: The Go extension is maintained by the Go team. Third-party extensions often lag behind language updates. Stick to the official extension. It receives patches for every Go release and integrates tightly with gopls.

The module requirement

gopls demands a go.mod file. It will not analyze code in a random directory. This prevents ambiguity. Without a module, gopls cannot resolve imports or determine the package path.

If you open a .go file without a go.mod, the status bar shows No go.mod file found. gopls disables most features until you initialize a module. Run go mod init in the terminal to create the file.

// main.go
package main

import "fmt"

// Main prints a greeting to stdout.
func main() {
    fmt.Println("gopls is working")
}

Once go.mod exists, gopls reads it to resolve dependencies. It downloads modules as needed. If you rename the module in go.mod, gopls might get confused until you restart the language server or update the file.

Convention aside: go.mod is the source of truth. gopls trusts it implicitly. If your imports don't match the module path, gopls reports errors. Keep the module path consistent with your repository structure.

Configure formatting and analysis

You usually don't need to touch settings, but sometimes you want to tweak formatting or enable stricter checks. gopls handles formatting via gofmt. You don't configure indentation in VS Code. You configure gopls, and gopls runs gofmt. The output is always gofmt style.

Tweak gopls behavior through VS Code settings. You can enable gofumpt for stricter formatting or turn on specific analyses.

{
  "gopls": {
    "formatting.gofumpt": true,
    "analyses": {
      "fieldalignment": true,
      "nonewvars": true
    }
  }
}

The gofumpt setting tells gopls to run gofumpt instead of gofmt. gofumpt enforces additional rules like grouping imports and removing unnecessary blank lines. The fieldalignment analysis suggests struct field reordering to reduce memory usage. The nonewvars analysis flags variables that are assigned but never read.

Convention aside: gofmt is mandatory in the Go community. Don't argue about indentation. Let the tool decide. Most editors run gofmt on save. gopls respects this convention. If you use gofumpt, ensure your team agrees on the style.

Debugging with Delve

VS Code integrates with Delve, the standard debugger for Go. Debugging requires a separate configuration file. Create a launch.json file in your .vscode directory.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch Package",
      "type": "go",
      "request": "launch",
      "mode": "debug",
      "program": "${fileDirname}"
    }
  ]
}

The type: go tells VS Code to use the Go extension's debugger adapter. The mode: debug starts the program under Delve control. The program: ${fileDirname} runs the current package. You can set breakpoints and inspect variables.

Convention aside: Delve is the standard debugger. dlv is the command-line tool. VS Code uses it under the hood. You can also run dlv debug in the terminal for headless debugging. The extension just provides a GUI for Delve.

Pitfalls and recovery

gopls can fail silently or throw errors. The Output panel is your friend. Open the Output panel and select the "Go" channel. You'll see logs from gopls and the extension.

If gopls fails to start, the Output panel shows gopls: failed to initialize. Check your Go version. gopls requires a compatible version. Go 1.22 requires gopls v0.15+. If you see a version mismatch, update your tools.

The compiler rejects code with gopls: version mismatch: gopls v0.13.0 is incompatible with Go 1.22 if the versions are too far apart. Run Go: Install/Update Tools to fix this.

Proxy issues are common. gopls needs to download dependencies. If your network blocks proxy.golang.org, gopls fails. Set GOPROXY in your environment or in VS Code settings.

The editor shows go: github.com/...: Get "https://proxy.golang.org/...": dial tcp ...: i/o timeout when the proxy is unreachable. Configure your proxy or use a mirror.

gopls caches results. Sometimes the cache gets stale. You need to run Go: Restart Language Server or Go: Invalidate Cache to force a refresh.

Section closer: gopls is the brain. VS Code is just the screen. When autocomplete dies, check the Output panel, not the code.

Decision matrix

Use VS Code with the Go extension when you want a lightweight editor with full language server support and a massive ecosystem of plugins. Use GoLand when you need deep refactoring, database tools, and Docker integration out of the box, and you don't mind the subscription cost. Use Neovim with gopls when you prefer keyboard-driven workflows and want to configure every keystroke, accepting the higher setup complexity. Use the plain go toolchain in the terminal when you are debugging build scripts or working on a server where GUI editors are unavailable.

Where to go next