# How the go-modern-guidelines CLI Determines the Target Go Version from go.mod

> Learn how the go-modern-guidelines CLI finds your target Go version. It checks flags, go.mod files, and falls back to your local toolchain.

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

---

**The go-modern-guidelines CLI determines the target Go version by checking for an explicit `--go-version` flag, parsing the `go` directive from `go.mod` or `go.work` files (searching upward through the directory tree if necessary), and falling back to the locally installed Go toolchain when no module file exists.**

The JetBrains/go-modern-guidelines repository provides a CLI tool that filters Go coding guidelines based on the target language version. When executing the `list` command, the tool must resolve which Go version to target so it can return the appropriate modern guidelines set. This resolution logic is centralized in the **`internal/goversion`** package, which implements a cascading priority system for version detection.

## Resolution Logic Overview

The entry point for version detection is the `goversion.Resolve` function, invoked by `runList` in [`internal/cli/cli.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/cli/cli.go) (lines 79-84). This function accepts three parameters: a file path, an explicit version string from the `--go-version` flag, and the latest known version from the guidelines package. The function implements a priority-based decision tree where explicit flags take precedence, followed by module file parsing, with a final fallback to the local Go installation.

## Explicit Version Flag Override

### The `--go-version` Flag

When the user supplies the `--go-version` flag, `goversion.Resolve` immediately normalizes the provided value and returns it. This override supports various formats including `1.24`, `go1.24.3`, or `devel` tags (internal/goversion/goversion.go, lines 18-27). This ensures developers can force specific guideline sets regardless of the project's module configuration.

```bash

# Force guidelines for Go 1.24 regardless of go.mod

$ go-modern-guidelines list --go-version=1.24

```

## Automatic Detection from Module Files

When no explicit version is provided, the CLI attempts to locate and parse module files automatically via `resolveGoVersionFromPath` (internal/goversion/goversion.go, lines 31-33).

### Direct File Parsing with `parseGoDirective`

If the supplied path points directly to a `go.mod` or `go.work` file, the code calls `parseGoDirective` (internal/goversion/goversion.go, lines 69-75). This function reads the file and uses `golang.org/x/mod/modfile` to extract the `go` directive value.

### Directory Traversal with `findUp`

When the provided path is a directory or a non-module file, the CLI walks upward through the filesystem hierarchy. The `findUp` utility (internal/goversion/goversion.go, lines 77-84 and 9-22) searches parent directories for the nearest `go.mod` or `go.work` file. Once found, the file is parsed using the same `parseGoDirective` logic as direct file handling.

```go
// Example: Resolve from a specific directory
version, err := goversion.Resolve("path/to/project", "", guidelines.LatestKnownVersion())
if err != nil {
    log.Fatal(err)
}
fmt.Println("Detected Go version:", version) // Output: "1.23"

```

### Fallback to Local Toolchain

If no module file is found during the directory traversal, the CLI executes `resolveGoToolVersion` (internal/goversion/goversion.go, lines 62-71). This function runs `go env GOVERSION` to retrieve the version of the locally installed Go toolchain, ensuring the tool remains functional even outside module-aware directories.

```bash

# CLI automatically detects version from nearest go.mod

$ go-modern-guidelines list

# If the current directory contains a go.mod with "go 1.23", 

# the output will be based on 1.23

```

## Version Normalization

All version strings—whether from flags, module files, or the local toolchain—pass through `normalizeGoVersion` (internal/goversion/goversion.go, lines 74-88). This function uses a regular expression to extract the **major.minor** pair (e.g., converting `go1.24.3` to `1.24`) and discards patch versions and suffixes. This normalization ensures consistent version comparison across different input formats.

## Summary

- The **`goversion.Resolve`** function in [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go) orchestrates version detection with explicit flags taking highest priority.
- **Explicit version override**: The `--go-version` flag bypasses automatic detection and normalizes inputs like `1.24` or `go1.24.3`.
- **Module file parsing**: The tool parses `go.mod` and `go.work` files using `golang.org/x/mod/modfile` to extract the `go` directive.
- **Directory walking**: If given a directory, the CLI searches upward via `findUp` to locate the nearest module file.
- **Toolchain fallback**: When no module file exists, the CLI falls back to the local Go version via `go env GOVERSION`.
- **Normalization**: All versions are standardized to `major.minor` format using `normalizeGoVersion` before guideline selection.

## Frequently Asked Questions

### How does go-modern-guidelines handle pre-release or development Go versions?

The CLI accepts development versions through the `--go-version` flag, including formats like `devel` or specific pre-release tags. The `normalizeGoVersion` function processes these strings and extracts the major.minor pair when possible, or preserves the development identifier for guideline matching according to the implementation in [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go).

### Can the tool detect versions from go.work files as well as go.mod?

Yes. The `parseGoDirective` function and `findUp` utility specifically search for both `go.mod` and `go.work` files. The `golang.org/x/mod/modfile` parser handles both file types, extracting the `go` directive that specifies the language version for the workspace or module.

### What happens if my project has no go.mod file?

If the directory traversal via `findUp` fails to locate a `go.mod` or `go.work` file, the CLI calls `resolveGoToolVersion` to execute `go env GOVERSION`. This retrieves the version of the currently installed Go toolchain and uses that as the target version for filtering guidelines.

### Why does the CLI normalize versions to major.minor format?

The `normalizeGoVersion` function strips patch versions and suffixes to ensure consistent comparison logic. Since Go language features and guidelines are typically gated at the minor version level (e.g., 1.21, 1.22), normalizing to `major.minor` allows the guideline database to match against stable version identifiers regardless of the specific patch level installed.