Lodash _.minBy() method

Beginner
⏱️ 6 min read
📚 Updated: May 2026
🎯 3 Code examples
🚀 3 Try-it labs
Lodash

What you’ll learn

  • How _.minBy(array, iteratee) resolves to baseExtremum(array, baseIteratee(iteratee, 2), baseLt) — the same engine as _.maxBy, opposite comparator.
  • Two iteratee shapes: a function or a _.property path string ('n', 'price.base').
  • What gets skipped: rows whose iteratee returns null, undefined, or NaN; the Symbol-position rule inherited from _.min.
  • Tie-breaking: the first element with the minimum score wins.
  • That empty / null input returns undefined — default with ??, not ||.

Prerequisites

Read _.min() first—_.minBy is the same factory with an iteratee plugged in. The skip rules and Symbol-position quirks documented there all apply here.

  • Iteratee shorthand: string → property path; function → itself; object → partial match.
  • baseExtremum loop: single pass, strict <, first-element-wins on ties.

Overview

Each element flows through baseIteratee(iteratee, 2) to produce a score. The score is the comparison key; the original element is what comes back. Inside the seed guard, any score that is null, undefined, NaN, or a Symbol fails to seed—those rows quietly drop out. Once seeded, baseLt (value < computed) decides replacements.

Score, not return

The iteratee picks the comparison key. _.minBy returns the original element, not the score.

Path shorthand

Dotted paths like 'price.base' drill into nested objects via _.property.

Missing fields skip

Rows where the path returns undefined are silently excluded—the comparison runs only on rows with the field.

Syntax

javascript
_.minBy(array, [iteratee = _.identity])
  • array: array to scan. Falsy / empty short-circuits to undefined.
  • iteratee: function or string property path. Default is _.identity—omit it on a plain-number array and you’ll get the same result as _.min(array).
  • Returns: the original element with the lowest projected score, or undefined.
1

Docs baseline — function, path, nested path

The function form and the _.property shorthand are interchangeable. Dotted paths drill into nested objects.

javascript
import minBy from "lodash/minBy";

const objects = [{ n: 1 }, { n: 2 }];

console.log(minBy(objects, function (o) { return o.n; })); // { n: 1 }
console.log(minBy(objects, "n"));                            // { n: 1 }

// Real-world: cheapest after discount
const products = [
  { name: "Laptop",     price: { base: 800, discount: 50 } },
  { name: "Smartphone", price: { base: 600, discount: 30 } },
  { name: "Tablet",     price: { base: 400, discount: 20 } }
];
console.log(minBy(products, p => p.price.base - p.price.discount));
// { name: "Tablet", price: { base: 400, discount: 20 } }

// Nested path shorthand
const temperatures = [
  { location: "City A", temperature: -5 },
  { location: "City B", temperature: 2 },
  { location: "City C", temperature: -10 }
];
console.log(minBy(temperatures, "temperature"));
// { location: "City C", temperature: -10 }
Try it Yourself
2

Missing fields, NaN, and ties

Rows missing the field are silently dropped from the contest (unlike _.meanBy, this gives the correct answer for the rows that have the field). NaN scores are skipped. Ties go to the first occurrence.

javascript
import minBy from "lodash/minBy";

// Missing field: silently skipped, still gets a correct min
console.log(minBy([{ n: 1 }, { x: 2 }, { n: 3 }], "n"));
// { n: 1 }

// Every row missing the field -> undefined
console.log(minBy([{ x: 1 }, { y: 2 }], "n"));
// undefined

// NaN scores are skipped
console.log(minBy([{ n: 5 }, { n: NaN }, { n: 1 }], "n"));
// { n: 1 }

// Ties: first occurrence wins (strict <)
console.log(minBy(
  [{ id: 1, n: 5 }, { id: 2, n: 3 }, { id: 3, n: 3 }],
  "n"
));
// { id: 2, n: 3 }
Try it Yourself
3

Empty input, default iteratee, BigInt & Symbols

Empty / null returns undefined. Omitting the iteratee falls back to _.identity—great for plain numeric arrays, useless for objects. BigInts compare normally; Symbol scores follow _.min’s position rule.

javascript
import minBy from "lodash/minBy";

console.log(minBy([], "n"));                       // undefined
console.log(minBy(null, "n"));                     // undefined

// Safe default with ??, not || (in case the min element has a falsy property)
const cheapest = minBy([], "price") ?? { price: Infinity };
console.log(cheapest);                              // { price: Infinity }

// No iteratee -> _.identity. Works for numbers, fails on objects.
console.log(minBy([5, 3, 8, 1, 4]));               // 1   (acts like _.min)
console.log(minBy([{ n: 3 }, { n: 1 }]));          // { n: 3 }
//                                                    ^ first object stays seeded:
//                                                    {n:1} < {n:3} is false (NaN)

// BigInt scores compare fine
console.log(minBy([{ n: 3n }, { n: 1n }, { n: 5n }], "n"));
// { n: 1n }

// Symbol after a seed throws (just like _.min)
try {
  console.log(minBy([{ n: 1 }, { n: Symbol("x") }, { n: 3 }], "n"));
} catch (err) {
  console.log("Threw:", err.message);              // "Cannot convert a Symbol value to a number"
}
Try it Yourself

📋 _.minBy vs _.min vs hand-rolled reduce

ApproachCodeNotes
_.min_.min(arr)Single-arg only; second argument is ignored. Compares values directly.
_.minBy (function)_.minBy(arr, o => o.price)Most flexible; iteratee can compute derived values like p.base - p.discount.
_.minBy (path)_.minBy(arr, 'price.base')Shorter; dotted paths supported via _.property.
Reducearr.reduce((m, o) => o.price < m.price ? o : m)Verbose; throws on empty; no NaN/undefined guard.

Pitfalls to avoid

Defaulting

Use ??

_.minBy(arr, 'n') || fallback is safer than for primitives (the return is an object, so usually truthy), but a null return from an empty array is still falsy. Prefer ?? or explicit === undefined.

Missing fields

Silent partial answers

Rows missing the field don’t throw and don’t poison the result—they just disappear. If you wanted a hard failure, validate the data first.

Iteratee shape

One argument only

The iteratee is invoked with (value)—no index, no array. Use reduce if you need them.

Ties

Order matters

When two elements tie for the minimum score, the first one wins. Sort or pre-filter if you need a different tie-breaker.

Symbols

Position rule applies

A Symbol score that appears after a non-Symbol seed will throw Cannot convert a Symbol value to a number. Filter symbols out of the data if they might appear.

❓ FAQ

_.min compares values directly using <. _.minBy(array, iteratee) projects each element through the iteratee first and compares the projections—then returns the original element with the lowest score. Use _.minBy for object arrays.
Yes. _.minBy(arr, 'price') is shorthand for _.minBy(arr, o => o.price). Dotted paths drill into nested objects: _.minBy(arr, 'price.base').
Their iteratee returns undefined and baseExtremum's seed guard skips them—the comparison only considers rows that DO have the field. _.minBy([{n:1},{x:2},{n:3}], 'n') is {n:1}, not undefined. (This is different from _.meanBy, which still divides by the full length.)
The first occurrence of the minimum wins. baseLt uses strict <, so a later element with the same score doesn't replace the running result.
null, undefined, and NaN scores are silently skipped. Symbol scores are skipped while looking for the first seed but throw if they appear after a valid seed (same root cause as _.min: < cannot operate on Symbols).
Yes—the < operator handles BigInts. _.minBy([{n:3n},{n:1n},{n:5n}], 'n') returns {n:1n}. Mixed BigInt + Number iteratee results also work for the comparison itself.

Summary

  • Purpose: find the “smallest” element by a derived score; returns the original element.
  • Remember: function or string-path iteratee; missing/null/undefined/NaN scores silently skipped; ties keep first occurrence; empty/null → undefined.
  • Next: Lodash _.multiply() for pairwise multiplication, or read the official Lodash docs for _.minBy.
Did you know?

_.minBy calls the iteratee with the documented arity hint (baseIteratee(iteratee, 2))—that's what lets 'price.base' drill into nested objects exactly like _.get(o, 'price.base') would, with no extra parsing on your end.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful