# Difference Between `any` and `interface{}` Usage Patterns in Go

> Understand the difference between any and interface{} in Go 1.18. Learn when to use any for modern, generic code and reserve interface{} for legacy APIs.

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

---

**`any` is a built-in type alias for `interface{}` introduced in Go 1.18 that produces identical compiled output but signals modern, generic-friendly code, whereas `interface{}` should be reserved for legacy contexts and non-generic APIs.**

The JetBrains/go-modern-guidelines repository establishes clear conventions for adopting post-generics Go idioms. While `any` and `interface{}` are functionally equivalent at the compiler level, they convey distinct semantic intentions that affect readability, maintenance, and type system design.

## Functional Equivalence and Historical Context

Both `any` and `interface{}` represent the empty interface type, meaning they can hold values of any concrete type. The critical distinction lies in their introduction timeline and intended usage patterns.

`interface{}` has been part of Go since its inception, serving as the language's universal container. `any` was added as a predeclared alias in Go 1.18 alongside generics support. According to the source code analysis in [`FEATURES.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md), this addition was specifically designed to provide clearer syntax for unconstrained type parameters.

Despite being separate identifiers, they compile to identical underlying types with zero performance difference.

## Generics Constraints and Type Parameters

The most significant technical divergence appears in generic programming contexts. As documented in [[`FEATURES.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md) at line 1808](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md#L1808), `interface{}` **cannot** be used as a type constraint, whereas `any` is explicitly designed for this purpose.

Attempting to use `interface{}` as a constraint results in a compilation error:

```go
// Illegal: interface{} cannot be used as a constraint
func Process[T interface{}](value T) { }

```

The correct modern pattern uses `any`:

```go
// Valid: any is designed for unconstrained generics
func Process[T any](value T) { }

```

This distinction makes `any` essential when defining functions that accept any type while participating in the generic type system.

## Code Migration Patterns

The guidelines in [[`FEATURES.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md) (lines 1820-1832)](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md#L1820-L1832) demonstrate the recommended migration from legacy signatures to modern idioms:

**Before (Legacy):**

```go
func Decode(v interface{}) error {
    return nil
}

```

**After (Modern):**

```go
func Decode(v any) error {
    return nil
}

```

For generic collections, prefer `any` to signal unconstrained flexibility:

```go
// Generic function accepting any slice type
func PrintAll[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}

```

Reserve `interface{}` for scenarios requiring explicit compatibility with pre-1.18 codebases:

```go
// Non-generic context maintaining legacy compatibility
func PrintLegacy(v interface{}) {
    fmt.Printf("%v\n", v)
}

```

## Repository Guidelines and Tooling

The official guideline states:

> "Use `any` instead of `interface{}`. `any` is the built-in alias for `interface{}` introduced with generics. Use it for unconstrained values and type parameters so the code reads in current Go terminology." — [[`FEATURES.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md) line 1810](https://github.com/JetBrains/go-modern-guidelines/blob/main/FEATURES.md#L1810)

This convention is enforced not only for human readability but also for automated tooling. The file [`plugin/skills/use-modern-go/SKILL.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/plugin/skills/use-modern-go/SKILL.md) indicates that these patterns are consumed by code generation agents, ensuring that AI-assisted development adheres to modern Go standards established in the [[`README.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/README.md)](https://github.com/JetBrains/go-modern-guidelines/blob/main/README.md).

## Summary

- **`any`** is the preferred choice for modern Go code, generic type parameters (`[T any]`), and conveying "unconstrained value" semantics.
- **`interface{}`** remains valid but should be restricted to legacy codebases, non-generic APIs, or when explicit backward compatibility is required.
- **Compiler impact** is identical; the difference is purely semantic and maintainability-focused.
- **Type constraints** represent the technical boundary where only `any` is permitted in generic contexts.

## Frequently Asked Questions

### Are `any` and `interface{}` interchangeable in Go?

Yes, they are fully interchangeable at the type system and runtime level because `any` is strictly a type alias for `interface{}`. You can assign values between them freely, and they compile to identical machine code. The difference lies exclusively in code readability and the ability to use `any` as a generic constraint.

### Can I use `interface{}` as a generic type constraint?

No, this is explicitly prohibited by the Go compiler. As noted in the JetBrains guidelines, `func Foo[T interface{}](v T)` is illegal syntax. You must use `any` (or a specific interface) when defining unconstrained type parameters in generic functions and types.

### Does switching from `interface{}` to `any` affect performance?

No, there is zero performance impact. Both identifiers resolve to the same underlying empty interface type during compilation. The change is purely cosmetic and semantic, aimed at aligning code with post-Go 1.18 idioms without altering runtime characteristics.

### When should I keep using `interface{}` instead of migrating to `any`?

Maintain `interface{}` when working with codebases that must compile on Go versions prior to 1.18, or when integrating with legacy libraries that explicitly expect the `interface{}` type in their public APIs. For all new development and internal refactoring, the guidelines recommend adopting `any`.