TL;DR: Const generics allow types and functions to be generic over constant values (integers, booleans, chars) rather than only types. The most important use case is arrays:
[T; N]whereNis a const generic; this is howstdimplements traits uniformly for arrays of any length. You writestruct Matrix<const ROWS: usize, const COLS: usize>and the compiler generates separate code for each distinct const value used.
What Are Const Generics?
Const generics are compile-time constant values used as type parameters; most commonly array sizes.
struct Matrix<const ROWS: usize, const COLS: usize> {
data: [[f64; COLS]; ROWS],
}
impl<const ROWS: usize, const COLS: usize> Matrix<ROWS, COLS> {
fn new() -> Self {
Self { data: [[0.0; COLS]; ROWS] }
}
fn rows(&self) -> usize { ROWS }
fn cols(&self) -> usize { COLS }
}
let m: Matrix<3, 4> = Matrix::new(); // 3×4 matrix, zero-cost abstractionMatrix<3, 4> and Matrix<5, 5> are distinct types at compile time; the compiler generates optimized code for each.
How Does std Use Const Generics?
Since Rust 1.51, [T; N] implements std traits uniformly for any N using const generics.
Before const generics, the standard library manually implemented traits like Debug, Clone, and PartialEq for arrays up to length 32. After const generics, one impl covers all sizes:
// This is how std now works internally:
impl<T: Debug, const N: usize> Debug for [T; N] {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { ... }
}This is why you can now use [u8; 64].clone() without worrying about whether 64 is in the "supported" list.
How Do You Write a Function With Const Generics?
Declare the const parameter with const N: usize in the generic list.
fn first_n<T: Copy, const N: usize>(slice: &[T]) -> Option<[T; N]> {
if slice.len() < N {
return None;
}
let mut arr = [slice[0]; N];
arr.copy_from_slice(&slice[..N]);
Some(arr)
}
let arr: Option<[i32; 3]> = first_n(&[1, 2, 3, 4, 5]);The caller can specify N explicitly or let the compiler infer it from context.
Const Generics vs Type Generics vs Trait Bounds in 2026
Const generics, type generics, and trait bounds each solve a different parameterization problem; knowing when to use which is key to idiomatic Rust.
| Const Generics | Type Generics | Trait Bounds | |
|---|---|---|---|
| Parameterized over | Constant values (usize, bool, char) | Types | Behavior / capabilities |
| Compile-time dispatch | ✅ Monomorphized | ✅ Monomorphized | ✅ (static) / ❌ (dyn) |
| Use case | Array sizes, fixed buffers | Collections, wrappers | Abstracting over behavior |
| Stable since | Rust 1.51 (2021) | Always | Always |
| Arithmetic on params | ⚠️ Nightly (generic_const_exprs) | N/A | N/A |
| Maintainer | Rust lang team | Rust lang team | Rust lang team |
In 2026, stable const generics cover the vast majority of real-world needs; fixed-size arrays, stack-allocated buffers, and compile-time dimension checks. Reach for type generics when abstracting over types, trait bounds when abstracting over behavior, and const generics when you need a type that carries a compile-time integer. Avoid typenum for new code; const generics replace it on stable Rust.
What Are the Current Limitations?
Const generic expressions (arithmetic on const params) are partially supported; complex expressions require nightly.
// Stable: simple const params
struct Buffer<const N: usize>([u8; N]);
// Nightly only: arithmetic in const expressions
// struct Doubled<const N: usize>([u8; N * 2]); // requires #![feature(generic_const_exprs)]On stable Rust, const parameters must be simple identifiers; you cannot use N + 1 or N * 2 as a type-level expression. The generic_const_exprs feature is tracked for stabilization.
Frequently Asked Questions
Stable Rust supports usize, u8–u128, i8–i128, bool, and char. Floats, strings, and structs are not yet supported as const generic parameters on stable.
Yes. The compiler monomorphizes each distinct const value, generating fully specialized code. There is no runtime dispatch or indirection.
typenum is a crate that encoded integers as types before const generics existed. It is largely superseded for new code in 2026, but older libraries (like nalgebra pre-2021) still use it for compatibility.
Use const generics when the value is known at compile time and you want the type system to enforce it; for example, [u8; 32] for a fixed-size crypto key. Use runtime parameters (usize fields) when the value varies per instance.
Yes. You can write trait FixedSize<const N: usize> { fn len() -> usize { N } }. This allows traits to be generic over a size parameter, enabling implementations like impl FixedSize<16> for MyKey {}.
Sources
- Rust Blog; Const Generics MVP
- Rust Reference; Const Generics
- Tracking issue: generic_const_exprs
- The Rust Book; Generic Data Types
Related Glossary Terms
- generic: Type generics, the more common form of parameterization
- associated-types: Another way to make traits flexible
- const-static: Compile-time constants (different from const generics)
- trait: Trait bounds are the companion tool to const generics
- impl-trait: Return-position impl Trait, another compile-time dispatch tool
Keep Reading
- Rust Generics and Traits: Const generics build on the generics system
- Rust vs Go in 2026: Where Rust's type system gives it a performance edge

