# How go-modern-guidelines Detects the Go Version Without Flags or File Paths

> Discover how go-modern-guidelines automatically detects your Go version using go env GOVERSION, ensuring tailored coding guideline application without flags or file paths.

- Repository: [JetBrains/go-modern-guidelines](https://github.com/jetbrains/go-modern-guidelines)
- Tags: internals
- Published: 2026-08-30

---

**When invoked without explicit inputs, the go-modern-guidelines CLI automatically queries the local Go toolchain via `go env GOVERSION`, normalizes the output to a major.minor format, and uses that value to filter applicable coding guidelines.**

The JetBrains/go-modern-guidelines tool analyzes Go source code against modern best practices, but it requires a target Go version to determine which rules apply. When you run the `list` command without specifying `--go-version` or `--file-path`, the CLI implements a sophisticated fallback chain that interrogates your local Go installation directly.

## The Auto-Detection Pipeline

The detection mechanism spans three logical layers: the command parser, the resolution engine, and the toolchain interface. This ensures that even in bare invocations, the linter evaluates code against the correct Go version constraints.

### Entry Point in the CLI Layer

The process begins in [`internal/cli/cli.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/cli/cli.go) within the `runList` function. This handler parses your command-line arguments and immediately delegates version resolution to the `goversion` package:

```go
targetVersion, err := goversion.Resolve(filePath, goVersion, guidelines.LatestKnownVersion())

```

If both `filePath` and `goVersion` are empty strings—meaning you provided no `--file-path` or `--go-version` flags—the `Resolve` function triggers the automatic detection sequence rather than returning an error.

### Resolution Logic in the goversion Package

Located in [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go), the `Resolve` function implements a priority-based fallback strategy:

1. Check for explicit version via `--go-version` flag
2. Check for module file via `--file-path` argument  
3. Fallback to local Go toolchain execution

When both inputs are empty, the function calls `resolveGoToolVersion` with a descriptive label and the latest known guideline version as a safety bound:

```go
return resolveGoToolVersion("local Go toolchain", develVersion)

```

### Executing the Toolchain Query

The `resolveGoToolVersion` function executes an external process call to extract the Go version from your environment:

```go
output, err := exec.Command("go", "env", "GOVERSION").Output()
version, err := normalizeGoVersion(string(output), develVersion)

```

This spawns `go env GOVERSION`, which returns the exact version string of the Go binary currently in your PATH (e.g., `go1.22.3`). The function captures stdout and passes it to the normalization routine to ensure consistent formatting.

### Normalizing the Version String

Raw toolchain output varies by installation (some distributions append build metadata or release candidates). The `normalizeGoVersion` function in [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go) sanitizes this using regex matching:

```go
match := goVersionInText.FindStringSubmatch(trimmed)
return fmt.Sprintf("%d.%d", majorMinor.major, majorMinor.minor), nil

```

This reduces strings like `go1.22.3` or `1.22rc1` to the canonical `major.minor` format (e.g., `1.22`) required by the guideline matrix. The CLI then compares this normalized version against its internal database of modern Go recommendations to determine which rules to display or enforce.

## Why Runtime Detection Over Build-Time

The go-modern-guidelines binary also defines a `detectedVersion()` function that reads `debug.ReadBuildInfo` to determine which Go version compiled the linter itself. However, the `list` command deliberately ignores this build-time constant.

**Runtime detection via `go env GOVERSION` ensures the linter evaluates your source code against the Go version you use to build that code, not the version used to build the linter.** This distinction matters in CI/CD environments where the linter binary might be compiled with Go 1.21 but is analyzing code intended for Go 1.22 deployment.

## Practical Usage Examples

### Automatic Detection (No Flags)

```bash
go-modern-guidelines list

```

*The CLI invokes `go env GOVERSION`, extracts the local toolchain version (e.g., 1.22), and displays guidelines applicable to that release.*

### Explicit Version Override

```bash
go-modern-guidelines list --go-version 1.20

```

*Bypasses auto-detection entirely; the specified version is normalized and used directly.*

### Module File Override

```bash
go-modern-guidelines list --file-path ./go.mod

```

*The CLI parses the `go` directive within the specified go.mod file, taking precedence over the local toolchain query.*

## Summary

- The `runList` function in [`internal/cli/cli.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/cli/cli.go) calls `goversion.Resolve` to determine the target Go version.
- When no flags are provided, `Resolve` falls back to `resolveGoToolVersion`, which executes `go env GOVERSION`.
- The `normalizeGoVersion` function converts the raw toolchain output (e.g., `go1.22.3`) into a standardized `major.minor` string.
- Auto-detection uses the runtime Go toolchain rather than the linter's build-time version to ensure accurate guideline matching for the code being analyzed.

## Frequently Asked Questions

### What happens if the `go` command is not in my PATH when I run go-modern-guidelines?

If the CLI cannot locate the `go` binary to execute `go env GOVERSION`, the `resolveGoToolVersion` function returns an error and the command fails. You must either add Go to your PATH or use the `--go-version` flag to specify the version manually.

### Can I force the CLI to use a different Go version than the one in my PATH?

Yes. Providing either `--go-version` or `--file-path` overrides the automatic detection entirely. The CLI does not execute `go env GOVERSION` when an explicit version source is provided.

### Why does the CLI report a different version than `go version` shows?

The CLI normalizes full version strings (e.g., `go1.22.3`) to their `major.minor` components (e.g., `1.22`) using the `normalizeGoVersion` function. This truncation allows the tool to match against guideline categories that apply to entire minor releases, rather than specific patch levels.

### Is there a way to see which version the CLI detected automatically?

While the CLI does not have a dedicated "verbose version detection" flag, running `go-modern-guidelines list` without arguments and observing which guidelines appear will indicate the detected version, as the output is filtered specifically for that Go release. You can verify the underlying value by running `go env GOVERSION` directly in your shell.