Over the last 2 years, I have been doing most of the development at Takt in Go. We chose Go due to its versatility for web services and background process code. Our team uses VSCode as our editor of choice and have tweaked our VSCode setup to meet our needs. In a future blog post I will talk about how we use Github Actions to deploy Go containers.

Obviously, “Best” is subjective and each editor setup needs to fit the individual and/or the team. These are what work for us and may not be best for you but hopefully, this serves as a starting point for your configuration.

To get started, it is important to understad the tools that we use within VSCode to support linting, formatting, and development.

  • goimports - goimports is a code formatter that organizes the imports at the top of your files and then runs go fmt.
  • golangci-lint - golangci-lint is a linting tool that supports running multiple linters across your codebase. It offers flexibility in configuration and runs quickly.
  • gopls - gopls is the Go language server. Editors use language servers as a standard for providing language specific features within the editor.

To install these tools we use Homebrew. I recommend following the instructions on each of the sites linked above to install. Once we have all of these tools installed, we need to configure VSCode to use these tools. We drop a project specific settings.json in each project using ./vscode/settings.json.

First, we have a couple base settings within the editor. These settings ensure the proper formatter is being used on our code and not inheriting settings from the users custom configuration.

{
  // prevent automatic formatting on code
  "editor.formatOnSave": false,
  "editor.formatOnPaste": false,
  "editor.formatOnType": false,
  // remove any code actions that are configured to run on save
  "editor.codeActionsOnSave": [],
  // put a ruler on the editing screen at 120 characters
  "editor.rulers": [120]
}

Now it is time to configure, Go.

// go specific settings
  "[go]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "golang.go",
    "editor.codeActionsOnSave": {
      "source.organizeImports": true,
      "source.fixAll": true,
    }
  },
  // make sure the go language server is enabled
  "go.useLanguageServer": true,
  // configure gopls, the go language server
  "gopls": {
    "ui.semanticTokens": true,
    "ui.completion.usePlaceholders": true
  },
  // configure the go formatting tool to be goimports
  "go.formatTool": "goimports",
  "go.formatFlags": [
    "-local",
    "github.com/takt-corp/"
  ],

  // change the linting tool to be golangci
  "go.lintTool": "golangci-lint",
  "go.lintOnSave": "workspace",
  "go.lintFlags": [
    "--fast"
  ],
  // configure the tags we want to add by default
  "go.addTags": {
    "tags": "json,validate",
    "options": "json=omitempty,validate=omitempty",
    "promptForTags": false,
    "transform": "snakecase",
    "template": ""
  },
  // dont run code coverage on save
  "go.coverOnSave": false,

This setup leverages the tools mentioned above automatically in the editor. Behaviorally, this means we use the language server for syntax highlighting and validation of code. We configure goimports to run on save so that the file is properly formatted. In addition to goimports, we also run golangci-lint on save across the entire project to catch any potential issues. If you have a large project, you may want to change it from “workspace” to a smaller scope.

Now that we have the editor setup it is time to configure the ./vscode/launch.json file so that we can run and debug our applications. We leverage a .env file (a.k.a “dotenv”) to configure our application and a few command line arguments. For most of our daily development, we use a tool called air which reloads the program when a file changes. I will conver in a later post, how we configure air and get air to work with VSCode.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch",
      "type": "go",
      "request": "launch",
      "mode": "debug",
      "program": "${workspaceFolder}/main.go",
      "args": ["server"],
      "envFile": "${workspaceFolder}/app.env"
    }
  ]
}

The above configuration will launch the application and start a debugging process. Note, your application args will likely be different. You will now be able to leverage all of the debugging tools within VSCode for your go application.

We are constantly tweaking our tools to help us write high quality code more efficiently. Hope this was helpful!