Skip to content

Linter ​

Overview ​

The Discord.js guide uses a linter to keep JavaScript consistent. In a Go project, formatting and baseline static analysis are built into the toolchain. gofmt is mandatory formatting, go vet catches suspicious constructs, and tests provide the behavioral check. Add a third-party linter only when the project agrees on its version and configuration.

Architecture ​

Formatting changes source text deterministically. go vet analyzes packages and reports likely bugs without running the bot. go test compiles every package and runs tests. None of these commands need a Discord token; the executable itself only connects when b.Run() is reached.

Prerequisites ​

  • Go 1.26.4 or newer.
  • A Go module containing the bot.
  • gofmt, go vet, and go test available through the Go installation.
  • A token and installed application only for the final runtime check.

Quick Start ​

Create main.go with the complete program below, then run the checks before starting the bot:

bash
export DISCORD_TOKEN='replace-with-a-bot-token'
go
package main

import (
	"log"
	"os"

	"github.com/discord-go/discord.go/bot"
	"github.com/discord-go/discord.go/intents"
)

func main() {
	token := os.Getenv("DISCORD_TOKEN")
	if token == "" {
		log.Fatal("DISCORD_TOKEN is required")
	}

	router := bot.NewRouter()
	router.Command("check", "Run a health check", func(ctx *bot.InteractionContext) {
		if err := ctx.Reply("The bot passed its runtime check."); err != nil {
			log.Printf("reply: %v", err)
		}
	})
	b := bot.New(token, bot.WithIntents(intents.Guilds), bot.WithRouter(router))
	b.OnError(func(err error) {
		log.Printf("runtime error: %v", err)
	})
	if err := b.Run(); err != nil {
		log.Fatal(err)
	}
}

Creating/Using ​

Run gofmt on changed .go files. Run go vet ./... from the module root so imports and all packages are checked. Run go test ./... in CI and before release. A linter should inspect code; it should not contain a bot token or make network calls merely to analyze a package.

Common Patterns ​

  • Add gofmt -w . or an equivalent file list to the development workflow.
  • Run go vet ./... and go test ./... on every pull request.
  • Use router.Validate() in a startup test for statically assembled commands.
  • Keep handlers small enough that static analysis and tests can exercise them.
  • Add a context timeout around REST calls in code that is not using context helpers.

Best Practices ​

  • Make formatting a CI gate rather than a personal preference.
  • Review lint suppressions individually and document the reason.
  • Use go test -race ./... when shared state is touched by concurrent handlers.
  • Keep generated code and generated command definitions separate from hand-written handlers.
  • Never suppress a warning by removing error handling from an interaction response.

Common Mistakes ​

Incorrect ​

go
_, _ = ctx.Reply("done")

Correct ​

go
if _, err := ctx.Reply("done"); err != nil {
	log.Printf("reply: %v", err)
}

Incorrect ​

bash
gofmt main.go

Correct ​

bash

The -w flag writes formatting changes, and the package-wide commands check more than the file currently open in an editor.

API Walkthrough ​

  • gofmt is the canonical Go formatter.
  • go vet performs standard static checks.
  • go test compiles packages and executes tests.
  • router.Validate checks command names, descriptions, handlers, and option definitions.
  • b.OnError reports runtime failures after the static checks have passed.

Examples ​

  • Slash Commands demonstrates validation and middleware.
  • Gateway demonstrates error handling for event decoding.
  • Full Template shows a layout suitable for larger applications.

Released under the Apache License 2.0.