Lodash _.findKey() method

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

What you’ll learn

  • How _.findKey(object, [predicate]) returns the first own string key whose value satisfies the predicate—or undefined when nothing matches.
  • The four predicate shorthands: function, string property, [key, value] pair, and partial-deep matcher object.
  • Why the matcher object uses nesting, not dotted paths like 'a.b.c'.
  • Try each example in the editor (?tryit=1, 2, 3) with Lodash from a CDN.

Prerequisites

Comfortable with Array.prototype.find; _.findKey is the same idea applied to an object’s keys.

  • Truthy-ish thinking: the predicate’s return value is evaluated for truthiness, so anything non-falsy short-circuits the search.
  • Lodash iteratee shorthands: string, array, and object shapes that Lodash converts to a function under the hood.
  • Own vs inherited keys: only own enumerable string keys are visited—same as Object.keys.

Overview

_.findKey scans an object’s own enumerable string keys in order. For each one it calls the predicate with (value, key, object) and returns the key of the first truthy result—or undefined if it walks the whole object without finding a match.

Returns the key

Unlike _.find (which returns the value), _.findKey hands back the matching property name so you can index back in.

Short-circuits on first match

Iteration stops as soon as the predicate returns truthy—cheap for large objects with an early hit.

Four shorthand shapes

Pass a function, a string property name, a [key, value] array, or a matcher object for partial-deep equality.

Syntax

javascript
_.findKey(object, [predicate=_.identity])
  • object: the source object whose own enumerable string keys are scanned.
  • predicate (optional): any value that _.iteratee accepts; defaults to _.identity (find the first key whose value is truthy).
  • Predicate signature: (value, key, object) => boolean.
  • Returns: the matching key (a string), or undefined when nothing matches.
1

Object matcher: find by a value’s property

Pass a plain object as the predicate and Lodash treats it as a partial-deep matcher against each value. Below, we hunt for the entry whose color is "yellow".

javascript
import findKey from "lodash/findKey";

const produce = {
  apple:  { color: "red",    type: "fruit" },
  banana: { color: "yellow", type: "fruit" },
  carrot: { color: "orange", type: "vegetable" }
};

findKey(produce, { color: "yellow" });
// -> "banana"

findKey(produce, { type: "vegetable" });
// -> "carrot"

findKey(produce, { color: "purple" });
// -> undefined   (no match)
Try it Yourself
2

Function predicate — remember the argument order

The predicate receives (value, key, object)—value first, like _.find. Forgetting that and reading key off the first parameter is the #1 mistake.

javascript
import findKey from "lodash/findKey";

const users = {
  user1: { age: 25, isAdmin: true  },
  user2: { age: 30, isAdmin: false },
  user3: { age: 22, isAdmin: true  }
};

findKey(users, (user) => user.isAdmin);
// -> "user1"   (first match wins)

findKey(users, "isAdmin");
// -> "user1"   (string shorthand: truthy on that property)

findKey(users, (user, key) => key.endsWith("3") && user.age < 30);
// -> "user3"   (full (value, key, object) signature)
Try it Yourself
3

Nested matcher: nest the predicate, don’t use dot paths

The object-shorthand matcher checks each predicate key as a literal property name. To match nested data, write the predicate with the same nesting; for a dotted-string path use _.matchesProperty via [path, value].

javascript
import findKey from "lodash/findKey";

const accounts = {
  jane:  { details: { name: "Jane Doe",   age: 28, isAdmin: false } },
  root:  { details: { name: "Admin User", age: 35, isAdmin: true  } }
};

findKey(accounts, { "details.isAdmin": true });
// -> undefined
//    "details.isAdmin" is a LITERAL key on the value; no such key exists.

findKey(accounts, { details: { isAdmin: true } });
// -> "root"          (nested matcher)

findKey(accounts, ["details.isAdmin", true]);
// -> "root"          ([path, value] shorthand expects a dotted path)
Try it Yourself

📋 _.findKey vs _.findLastKey vs _.find

Topic_.findKey_.findLastKey_.find
ReturnsMatching key (string)Matching key (string)Matching value
Works onObjectsObjectsArrays & objects
Iteration orderForward (insertion)ReverseForward (insertion)
No-match resultundefinedundefinedundefined
Predicate args(value, key, object)(value, key, object)(value, indexOrKey, collection)

Reach for _.findKey when you need the property name; if you only care about the matched value, _.find is a touch more direct.

Pitfalls to avoid

Arg order

Predicate gets (value, key), not (key, value)

If you swap them you’ll test the value as if it were a key. The fix is to remember: it’s _.find’s signature plus a key argument—value comes first.

Matcher

Dotted keys in object matcher are NOT paths

Old write-ups sometimes show { 'a.b.c': value } and claim it matches nested data. It doesn’t—_.matches reads "a.b.c" as a literal property name. Use a nested object or the [path, value] shorthand.

Truthy

Returning 0, "", or null is “no match”

Lodash checks predicate truthiness. If a real domain value should match but is falsy, wrap with an explicit === expected check.

No-match

Guard undefined before indexing

obj[_.findKey(obj, pred)] becomes obj[undefined] when there’s no match—rarely what you want. Check the key first or use _.find if you just need the value.

❓ FAQ

undefined. Always guard the result before using it as a key, e.g. const key = _.findKey(obj, pred); if (key !== undefined) { ... }.
(value, key, object). Value comes first&mdash;the same shape as _.find for collections&mdash;not (key, value) like Object.entries-style loops. Forgetting this is the most common bug.
Anything Lodash's _.iteratee accepts: (1) a function, (2) a string property name (truthy test on that key), (3) an array [key, value] for an equality check, and (4) an object treated as a partial-deep matcher against each value.
No. The matcher uses Lodash's _.matches, which treats each key as a LITERAL property name and recurses by nesting&mdash;not by splitting on dots. Use a nested object like { a: { b: { c: 1 } } }, or supply a function predicate, or use _.matchesProperty.
Own enumerable string-keyed properties only. Inherited keys and symbol keys are skipped. Iteration order is the engine's standard property order (typically insertion order for string keys).
_.find returns the matched VALUE (works on arrays and objects); _.findKey returns the matched KEY (objects only). Same predicate rules otherwise.
Same behavior, opposite iteration direction. _.findLastKey walks the keys in reverse and returns the last match.

Summary

Did you know?

The predicate is invoked with (value, key, object)—value FIRST, key second. This mirrors _.find for collections; it’s the opposite of Object.keys(obj).find((key) => ...), where you naturally start from the key.

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