# How to Find the Minimum or Maximum of Values in Modern Go

> Discover the modern Go way to find min or max values using slices.Min and slices.Max in Go 1.21+. Simplify your code and avoid manual loops.

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

---

**Use `slices.Min` and `slices.Max` from the Go 1.21+ standard library to extract the smallest or largest element from ordered slices without writing manual comparison loops.**

The JetBrains/go-modern-guidelines repository establishes that the modern Go way to find the minimum or maximum of values relies on standard library helpers rather than traditional iteration. These functions eliminate boilerplate code, reduce error-prone comparison logic, and clearly signal intent when working with ordered types.

## Why Use slices.Min and slices.Max

According to the JetBrains/go-modern-guidelines source code, you should **use `slices.Max` and `slices.Min` instead of manual loops over ordered values**. This guideline appears in [`FEATURES.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md) at lines 1264–1266 and is encoded in the machine-readable [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json) at lines 935–948.

The `slices` package provides these functions specifically for ordered constraints—any type that supports `<`, `<=`, `>`, or `>=` operators. This includes:

- **Integer types** (`int`, `int64`, `uint`, etc.)
- **Floating-point types** (`float32`, `float64`)
- **Strings** (compared lexicographically)

Introduced in Go 1.21 and fully supported for Go 1.25+ in the guidelines, these functions transform verbose loop-and-compare patterns into single, readable function calls.

## Working with Ordered Types

The `slices.Min` and `slices.Max` functions accept a slice of any ordered type and return the corresponding extreme value. The type constraint `constraints.Ordered` (from the `golang.org/x/exp/constraints` package in earlier versions, now integrated into the standard library) ensures compile-time safety.

When you pass a slice to these functions, they perform an optimized linear scan internally—equivalent to the manual loop you would write, but without the risk of off-by-one errors or incorrect initial value assignments.

## Practical Code Examples

Here is how to apply the modern approach across different ordered types:

```go
package main

import (
	"fmt"
	"slices"
)

func main() {
	// Integer slice – find max & min
	ints := []int{42, 7, 19, 33}
	maxInt := slices.Max(ints) // 42
	minInt := slices.Min(ints) // 7
	fmt.Printf("int  max=%d  min=%d\n", maxInt, minInt)

	// Float slice – works with any ordered type
	floats := []float64{3.14, 2.71, 1.62}
	fmt.Printf("float max=%g  min=%g\n", slices.Max(floats), slices.Min(floats))

	// String slice – lexicographic ordering
	names := []string{"alice", "bob", "charlie"}
	fmt.Printf("lexicographic max=%s  min=%s\n", slices.Max(names), slices.Min(names))
}

```

The `go.mod` file in the JetBrains/go-modern-guidelines repository specifies a minimum Go version of 1.25, ensuring the `slices` package is available without external dependencies.

## Critical Safety Considerations

**Never call these functions on empty slices.** Both `slices.Min` and `slices.Max` panic if the provided slice has length zero. You must explicitly guard against emptiness:

```go
if len(values) == 0 {
    // Handle empty case appropriately
    return 0, errors.New("empty slice")
}
return slices.Max(values), nil

```

## When to Stick with Manual Loops

While the modern standard library approach covers most scenarios, explicit iteration remains necessary in two specific cases:

1. **Empty slice handling**: When you need to return a zero value or error instead of panicking.
2. **Custom comparisons**: When working with structs or complex types requiring non-standard ordering (e.g., comparing `User` structs by age field).

For custom ordering, either maintain an explicit loop or use `sort.Slice` to sort the collection first, then access the first or last element.

## Summary

- **Use `slices.Min` and `slices.Max`** for cleaner, idiomatic code when finding extremes in ordered slices.
- **Verify slice length** before calling these functions to avoid runtime panics.
- **Prefer manual loops or sorting** only when handling empty collections or implementing custom comparison logic.
- **Reference [`FEATURES.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md)** and [`guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/guidelines.json) in the JetBrains/go-modern-guidelines repository for the canonical implementation rules.

## Frequently Asked Questions

### What happens if I call slices.Min or slices.Max on an empty slice?

Both functions panic at runtime. The implementations require at least one element to establish a baseline for comparison. Always check `len(slice) > 0` before invocation, or use a manual loop that returns a default value for empty inputs.

### Can I use slices.Min and slices.Max with custom structs?

No. These functions only accept types satisfying the `Ordered` constraint (numbers and strings). For structs or types requiring custom comparison logic, implement an explicit loop or define a `Less` method and use `sort.Slice` or `slices.SortFunc` followed by index access.

### What Go version do I need to use these functions?

You need Go 1.21 or later, where the `slices` package entered the standard library. The JetBrains/go-modern-guidelines repository specifically targets Go 1.25+ in its `go.mod` file, ensuring full compatibility with the latest slice manipulation utilities.