How to set up Vim for Go Development
Tags: go, vim, ide
Published: 2021-04-11 08:35:41

---
title: How to set up Vim for Go Development
published: true
description: A guide on setting up your Vim environment for Go development in production systems
tags: golang, vim, ide
cover_image: https://i0.wp.com/pmihaylov.com/wp-content/uploads/2021/04/vim-cover.png?resize=513%2C266&ssl=1
---
<!-- wp:paragraph -->
<p>One of the major reasons I love programming in Go is that I can do it in any IDE or editor I want, including my favourite <a href="https://pmihaylov.com/category/boost-your-vim/" target="_blank" rel="noreferrer noopener">Vim editor</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Unlike Java, for example, which is highly coupled to IntelliJ or Eclipse, Go is much more lightweight and the tools you use with it can be integrated with any editor.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In this guide, I will help you setup your Vim as a fully-fledged Go IDE, including the plugins you need to install but also setting up the important options &amp; mappings which you'll use daily.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Prerequisites</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>You'll need to have <a href="https://golang.org/doc/install">Go installed</a> &amp; your Go environment setup, namely your <strong>$GOPATH</strong> and related subdirectories - <strong>/bin /pkg /src</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You'll also need to use <a href="https://github.com/neovim/neovim">nvim</a> instead of vim or have your vim updated to version 8+.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>The Main Vim plugin for Go</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>One of the only plugins you need for Go is called <a href="https://github.com/fatih/vim-go">vim-go</a>. It aggregates all the tools you need to get started with Go development.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To install it via <a href="https://github.com/tpope/vim-pathogen">pathogen</a>:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>git clone https://github.com/tpope/vim-pathogen ~/.vim/bundle</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p><a href="https://github.com/fatih/vim-go#install">Other installation options</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After you've installed it, you can customise it using these options which are highly opinionated, but work best for me:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>" disable all linters as that is taken care of by coc.nvim
let g:go_diagnostics_enabled = 0
let g:go_metalinter_enabled = &#91;]

" don't jump to errors after metalinter is invoked
let g:go_jump_to_error = 0

" run go imports on file save
let g:go_fmt_command = "goimports"

" automatically highlight variable your cursor is on
let g:go_auto_sameids = 0
</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>For syntax highlighting, use these options:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>let g:go_highlight_types = 1
let g:go_highlight_fields = 1
let g:go_highlight_functions = 1
let g:go_highlight_function_calls = 1
let g:go_highlight_operators = 1
let g:go_highlight_extra_types = 1
let g:go_highlight_build_constraints = 1
let g:go_highlight_generate_tags = 1</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Finally, install all the required go tools by opening vim and running:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>:GoInstallBinaries</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2>coc.nvim - Autocompletion &amp; linting</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In the past, I've relied on <a href="https://github.com/ycm-core/YouCompleteMe" target="_blank" rel="noreferrer noopener">YouCompleteMe</a> for auto-completion or <a href="https://github.com/fatih/vim-go">vim-go</a>'s native integration with vim for auto-completion &amp; <a href="https://github.com/dense-analysis/ale" target="_blank" rel="noreferrer noopener">ALE</a> for linting/static code analysis.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Nowadays, I prefer using <a href="https://github.com/neoclide/coc.nvim" target="_blank" rel="noreferrer noopener">coc.nvim</a> and its plugins to do all that as I've found it to be more reliable than all of those tools.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For installation instructions, follow the <a href="https://github.com/neoclide/coc.nvim#quick-start" target="_blank" rel="noreferrer noopener">Quick Start</a> guide.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>After you've installed it, run this command to install the necessary coc extension for Go:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>vim -c 'CocInstall -sync coc-go coc-html coc-css coc-json|q'</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>The html/css/json extensions are optional but who doesn't deal with those nowadays. You'd probably need them at some point.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Afterwards, open vim &amp; type <strong>:CocConfig</strong> to open coc's configuration file. These are my opinionated settings, stripped from the non-go related settings:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>{
  "suggest.noselect": false,
  "diagnostic.errorSign": "✘",
  "diagnostic.warningSign": "!",
  "diagnostic.infoSign": "?",
  "diagnostic.checkCurrentLine": true,
  "coc.preferences.formatOnSaveFiletypes": &#91;
    "javascript",
    "html",
    "json",
    "css",
    "scss",
    "go"
  ],
  "coc.preferences.hoverTarget": "float",
  "languageserver": {
    "golang": {
      "command": "gopls",
      "rootPatterns": &#91;"go.mod"],
      "filetypes": &#91;"go"]
    }
  },
  "go.goplsOptions": {
    "staticcheck": true
  }
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>For all auxiliary coc settings, add <a href="https://github.com/preslavmihaylov/dotfiles/blob/master/vim/coc.vim">these settings</a> to your .vimrc.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Mappings For The Most Useful Commands</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Having great tools is not enough. You need to know how to use them. Hence, it is best to customize some of the mappings which vim-go and coc provide you so that you're more effective when dealing with Go code.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here are the mappings I use most often and the way I've configured them:</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Manage unit tests in the current file</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>I've mapped running all the tests in the current file to &lt;leader&gt;-t which translates to \ + t on my Mac &amp; Linux.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;t  &lt;Plug&gt;(go-test)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>I've also mapped \ + tt to run the current test function only, instead of running all of them:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;tt &lt;Plug&gt;(go-test-func)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Finally, I use \ + c to toggle the coverage profile for the current file I'm in:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;c  &lt;Plug&gt;(go-coverage-toggle)</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":3} -->
<h3>Inspect a Go Codebase</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Show the function signature for a given routine with \ + i:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;i  &lt;Plug&gt;(go-info)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Show the interfaces a type implements with \ + ii:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;ii  &lt;Plug&gt;(go-implements)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Describe the definition of a given type with \ + ci:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;ci  &lt;Plug&gt;(go-describe)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>See the callers of a given function with \ + cc:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>autocmd BufEnter *.go nmap &lt;leader&gt;cc  &lt;Plug&gt;(go-callers)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Find all references of a given type/function in the codebase with \ + cr:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>nmap &lt;leader&gt;cr &lt;Plug&gt;(coc-references)</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Go to definition/Go back with Ctrl+d and Ctrl+a:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>nmap &lt;C-a&gt; &lt;C-o&gt;
nmap &lt;C-d&gt; &lt;Plug&gt;(coc-definition)</code></pre>
<!-- /wp:code -->

<!-- wp:heading {"level":3} -->
<h3>Refactor Go Code</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Not many options here, but there's renaming the symbol your cursor is on with \ + r:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>nmap &lt;leader&gt;r &lt;Plug&gt;(coc-rename)</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2>Occasional Maintenance of Tooling</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To update all Go tools, run this from vim:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>:GoUpdateBinaries</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>And updating all coc plugins:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>:CocUpdate</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>To upgrade vim-go or coc.nvim, delete the folders from <strong>~/.vim/bundle</strong> and git clone the repos again.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Setup The Cool gruvbox Theme (Optional)</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Install <a href="https://github.com/morhetz/gruvbox" target="_blank" rel="noreferrer noopener">gruvbox</a> using pathogen:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>git clone https://github.com/morhetz/gruvbox ~/.vim/bundle</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Enable it in your <strong>.vimrc</strong> with some opinionated extra options:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>colorscheme gruvbox
autocmd ColorScheme * highlight CocErrorFloat guifg=#ffffff
autocmd ColorScheme * highlight CocInfoFloat guifg=#ffffff
autocmd ColorScheme * highlight CocWarningFloat guifg=#ffffff
autocmd ColorScheme * highlight SignColumn guibg=#adadad</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Want to see how it looks?</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":1463,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://pmihaylov.com/wp-content/uploads/2021/03/gruvbox-1024x492.png" alt="" class="wp-image-1463"/></figure>
<!-- /wp:image -->

<!-- wp:heading -->
<h2>Setup tmux For Terminal Multiplexing (Optional)</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>If you want to manage multiple terminal tabs in the same window, use <a href="https://github.com/tmux/tmux/wiki">tmux</a> (See my <a href="https://pmihaylov.com/tmux-terminal-multiplexer/">how to guide</a>):</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":694} -->
<figure class="wp-block-image"><img src="http://pmihaylov.com/wp-content/uploads/2018/05/Selection_018-1024x576.png" alt="" class="wp-image-694"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>This is one of the most useful tools I have setup because it allows me to do my code editing in vim and manage all sorts of other terminal-related tasks in separate tabs all inside the same window.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>And that's everything I use for my daily Go programming. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This setup has worked extremely well for me and have in mind that I'm also dealing with <a href="https://eng.uber.com/go-monorepo-bazel/">Uber's huge Go Monorepo</a>, where I've been able to integrate my vim environment seamlessly (with some extra settings which you probably won't need.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>If you want to see my entire vim development environment, check out all my <a href="https://github.com/preslavmihaylov/dotfiles" target="_blank" rel="noreferrer noopener">dotfiles</a> and <a href="https://github.com/preslavmihaylov/default-setups" target="_blank" rel="noreferrer noopener">default-setups</a> repos, which include my full setup, including external programs, the terminal, vim, tmux, colorschemes, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Happy Gophing!</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Check out some of my other Go series:<br><a href="https://pmihaylov.com/series-integrating-go-with-elk/" target="_blank" rel="noreferrer noopener">Integrating your Go Service with ELK</a><br><a href="https://pmihaylov.com/grpc-with-go-crash-course/" target="_blank" rel="noreferrer noopener">gRPC With Go Crash Course</a></p>
<!-- /wp:paragraph -->