jsguides

Math.min()

Math.min([value1[, value2[, ...]]])

Math.min() returns the lowest value from zero or more numbers. It’s the counterpart to Math.max() and essential for clamping values, finding bounds, and enforcing minimum thresholds in your code.

Syntax

Math.min()
Math.min(value1)
Math.min(value1, value2)
Math.min(value1, value2, ..., valueN)

Parameters

ParameterTypeDefaultDescription
value1, ..., valueNnumberZero or more numbers to compare

Return Value

The smallest of the given numbers. Returns Infinity when called with no arguments.

Examples

Basic usage with numbers

Math.min(5, 3, 8, 1);
// 1

Math.min(42);
// 42

Math.min(-10, -5, -20);
// -20

Math.min(100, 50);
// 50

The examples above all pass at least one argument. With no arguments, Math.min() returns Infinity — a deliberate choice that gives the function a neutral identity element for folding operations like reduce(). Understanding this edge case matters when you pass dynamically sized arrays.

Empty argument list returns Infinity

A unique behavior that is the identity element for Math.min():

Math.min();
// Infinity

// This matters when reducing arrays:
const values = [];
values.reduce((a, b) => Math.min(a, b), Infinity);
// Infinity (for empty array)

The empty-argument identity makes Math.min() work naturally with reductions, but real-world code nearly always passes at least one value. When that value comes from an array, the spread operator provides the most readable way to apply Math.min() to its contents without manual unpacking.

Using the spread operator with arrays

Apply Math.min() to array contents using the spread operator:

const numbers = [5, 2, 8, 1, 9, 3];

Math.min(...numbers);
// 1

Math.max(...numbers);
// 9

// Compare without spread (doesn't work):
Math.min([5, 2, 8]);
// NaN - arrays are not unpacked automatically

The spread operator handles arrays of numbers cleanly, but real-world data is rarely that tidy. When arrays contain mixed types — strings, null, undefined — the results depend on JavaScript’s coercion rules, and a single non-coercible value can turn the entire output into NaN.

Handling non-numeric values

Math.min() coerces strings and null, but returns NaN for undefined, objects, and symbols:

// Coerced to numbers
Math.min('5', '2', '8');
// 2

Math.min(null, 0, -5);
// -5 (null coerces to 0)

Math.min(1, undefined);
// NaN (undefined cannot coerce)

// Objects and arrays return NaN
Math.min({}, []);
// NaN

// Practical: filter valid numbers first
const mixed = [5, '2', null, undefined, 8];
const valid = mixed.filter(n => typeof n === 'number' && !isNaN(n));
Math.min(...valid);
// 2

Filtering ensures you work with clean inputs, but Math.min() is rarely used alone. Its most common real-world application is clamping — keeping a value pinned between a minimum and a maximum. The pattern combines Math.min() and Math.max() in a single expression that bounds a number from both sides.

Common use case: Clamping a value

The classic pattern for constraining a number within bounds:

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

// Prevent value from going below minimum
clamp(5, 10, 100);
// 10

// Prevent value from going above maximum
clamp(200, 10, 100);
// 100

// Value within range stays unchanged
clamp(50, 10, 100);
// 50

// Real-world: ensure scroll position stays in bounds
const scrollY = Math.min(Math.max(currentScroll, 0), maxScroll);

The clamp pattern combines both functions into a single constraint, but Math.min() and Math.max() are worth understanding separately as well. They act as mirror images of each other — the same API, the same coercion rules, but opposite comparison directions. The symmetry between them makes them easy to learn together.

Math.min() vs Math.max()

They mirror each other but have one key difference:

// Symmetric behavior
Math.min(1, 2, 3);  // 1
Math.max(1, 2, 3);  // 3

// Empty arguments: inverse identities
Math.min();  // Infinity
Math.max();  // -Infinity

The symmetry between the two functions is straightforward when you pass numbers, but edge cases reveal subtler behavior. NaN propagation, infinity handling, and signed zero comparison all affect what Math.min() returns — and knowing these details prevents bugs in validation and boundary logic.

Edge Cases

Math.min(NaN, 1, 2);
// NaN - any NaN input propagates

Math.min(Infinity, 100);
// 100

Math.min(-Infinity, -100);
// -Infinity

Math.min(0, -0);
// -0 (negative zero is smaller)

Spread operator limitations

The spread operator works for Math.min() with small to moderate arrays, but very large arrays (hundreds of thousands of elements) can cause a stack overflow because spread unpacks every element as a function argument. For large arrays, use reduce() instead:

const huge = new Array(1000000).fill(0).map((_, i) => i);

// May throw RangeError for very large arrays:
Math.min(...huge);

// Safe for any size:
huge.reduce((min, v) => v < min ? v : min, Infinity);

Math.min() with NaN

If any argument is NaN, or converts to NaN, Math.min() returns NaN. This propagation is important for validation — passing unvalidated user input directly to Math.min() can silently produce NaN. Filter or validate values with Number.isFinite() before passing them.

Performance Tip

For finding minima in large arrays, prefer the spread operator over apply():

// Modern and clean
Math.min(...arr);

// Older alternative (works but less readable)
Math.min.apply(null, arr);

Both perform similarly on modern engines—choose readability.

When Math.min() is useful

Math.min() is the easiest way to find the lower bound in a set of numbers. It shows up in clamping logic, layout calculations, and any code that needs to keep a value from dropping below a floor. Because it accepts any number of arguments, it is convenient both for small comparisons and for array data spread into a call.

The empty-argument behavior is also worth knowing. Returning Infinity gives Math.min() a natural identity value, which makes it easy to fold into a reduction. That is one reason it fits so neatly into helper functions that combine or constrain values.

NaN and Coercion

Math.min() converts values using JavaScript’s usual numeric coercion rules. That can be handy with simple inputs, but it also means bad values can turn the entire result into NaN. If user input is involved, validate first with Number.isFinite() so a single broken value does not poison the whole calculation.

When you compare it to Math.max(), the two functions are mirror images with opposite identity values. That symmetry makes them easy to remember, and it is part of why they work so well together in clamp helpers.

See Also