Lodash _.cond() Method

Beginner
⏱️ 8 min read
📚 Updated: Jul 2026
🎯 6 Examples + 3 Try It
Util utilities

What You’ll Learn

By the end of this tutorial, you’ll turn long if/else chains into reusable functions with Lodash’s _.cond() and predicate–handler pairs.

01

Core Syntax

Build _.cond([[pred, fn], ...]) tables of rules.

02

First Match Wins

Lodash stops at the first truthy predicate.

03

Default Branch

End with [_.stubTrue, handler] as catch-all.

04

Shared Args

Predicates and handlers receive the same call arguments.

05

Real Rules

Map scores, temperatures, and HTTP status codes.

06

vs switch

Know when a plain if/else or switch is clearer.

What Is _.cond()?

_.cond() is a Lodash util helper that builds a conditional function from an array of [predicate, handler] pairs. Think of it as a functional if/else ladder: each predicate tests the incoming arguments; the first one that returns a truthy value runs its paired handler, and that handler’s return value is what _.cond() gives back.

💡
Beginner tip

Picture a row of doors. Lodash walks left to right; the first door whose lock (predicate) opens lets you into the room (handler) behind it. Put specific doors before general ones, and leave a final _.stubTrue door as the default fallback.

This pattern keeps branching logic in one declarative table instead of nested if statements—useful for categorizers, routers, and validators you want to pass around as first-class functions.

📝 Syntax

Pass an array of two-element pairs—predicate first, handler second:

javascript
_.cond(pairs)

Syntax Rules

  • pairs — array of [predicate, handler] tuples.
  • predicate — function returning truthy/falsy; receives the same args as the cond function.
  • handler — runs when its predicate matches; receives the same args.
  • Order — first matching pair wins; later pairs are skipped.
  • No match — returns undefined unless a _.stubTrue default pair exists.
javascript
import cond from "lodash/cond";
import stubTrue from "lodash/stubTrue";

const getSizeCategory = cond([
  [(value) => value < 10, () => "Small"],
  [(value) => value < 20, () => "Medium"],
  [(value) => value < 30, () => "Large"],
  [stubTrue, () => "Huge"]
]);

console.log(getSizeCategory(5));   // "Small"
console.log(getSizeCategory(35));  // "Huge"

⚡ Quick Reference

TaskCode patternResult
Create cond fnconst fn = _.cond(pairs)Returns conditional function
Default branch[_.stubTrue, handler]Always matches last
Range check[(n) => n < 0, () => "neg"]Predicate on first arg
Type guard[_.isString, (s) => s.trim()]Handler uses same arg
No match_.cond([[() => false, fn]])()undefined
Native alternativeif / else if / elseImperative equivalent
Returns
Function

New cond function

Evaluation
First match

Short-circuit order

Default
_.stubTrue

Catch-all predicate

Category
Util

Functional helper

🧰 Parameters

Structure of each pair passed to _.cond():

pairs Required

Array of two-element arrays. Each inner array is [predicate, handler]. An empty array produces a function that always returns undefined.

_.cond([[pred, fn], ...])
predicate Per pair

Function tested with the same arguments the cond function receives. Any truthy return selects this pair. Falsy skips to the next pair.

[(code) => code === 404, ...]
handler Per pair

Runs only when its predicate matches. Return value becomes the result of the cond function call. Receives identical arguments.

[(n) => "Score: " + n]
return value Function

The conditional function Lodash builds. Call it later with any arguments; evaluation happens at call time, not when _.cond() runs.

const route = _.cond(pairs)

Extract repeated predicates into named functions (isEven, is404) to keep pair tables readable and testable.

Examples Gallery

Practical _.cond() patterns with copy-ready code, sample output, and interactive Try It Yourself labs.

📚 Getting Started

Categorize numeric ranges with ordered predicate pairs.

Example 1 — Size category from a number

Map a value to Small / Medium / Large / Huge using ascending range checks and a _.stubTrue default.

javascript
const getSizeCategory = _.cond([
  [(value) => value < 10, () => "Small"],
  [(value) => value < 20, () => "Medium"],
  [(value) => value < 30, () => "Large"],
  [_.stubTrue, () => "Huge"]
]);

console.log(getSizeCategory(5));   // "Small"
console.log(getSizeCategory(15));  // "Medium"
console.log(getSizeCategory(25));  // "Large"
console.log(getSizeCategory(35));  // "Huge"
Try It Yourself

How It Works

Lodash tests value < 10 first. For 15, that fails; value < 20 passes, so Medium runs. Values 30+ fall through to _.stubTrue.

Example 2 — Letter grade from a score

Handlers receive the score and return a letter—predicates and handlers share the same argument.

javascript
const toLetter = _.cond([
  [(score) => score >= 90, (score) => "A (" + score + ")"],
  [(score) => score >= 80, (score) => "B (" + score + ")"],
  [(score) => score >= 70, (score) => "C (" + score + ")"],
  [(score) => score >= 60, (score) => "D (" + score + ")"],
  [_.stubTrue, (score) => "F (" + score + ")"]
]);

console.log(toLetter(92));  // "A (92)"
console.log(toLetter(74));  // "C (74)"
console.log(toLetter(55));  // "F (55)"
Try It Yourself

How It Works

Put highest thresholds first (90 before 80). If you reversed the order, every score >= 60 would match the first passing predicate incorrectly.

📈 Practical Patterns

HTTP status routing, temperature labels, and edge-case guards.

Example 3 — HTTP status message router

Route numeric status codes to user-facing messages—similar to error-handling switches in API clients.

javascript
const statusMessage = _.cond([
  [(code) => code >= 500, () => "Server error — try again later"],
  [(code) => code === 404, () => "Resource not found"],
  [(code) => code === 403, () => "Access denied"],
  [(code) => code >= 400, () => "Bad request"],
  [(code) => code >= 200 && code < 300, () => "Success"],
  [_.stubTrue, (code) => "Unknown status: " + code]
]);

console.log(statusMessage(200));  // "Success"
console.log(statusMessage(404));  // "Resource not found"
console.log(statusMessage(503));  // "Server error — try again later"
Try It Yourself

How It Works

Check 500-range before generic 400-range so 503 does not fall into “Bad request.” Exact codes like 404 sit before broader buckets.

Example 4 — Temperature label

Transform a Celsius reading into a human-readable weather category.

javascript
const getTemperatureLabel = _.cond([
  [(temp) => temp < 0,  () => "Freezing"],
  [(temp) => temp < 10, () => "Cold"],
  [(temp) => temp < 25, () => "Moderate"],
  [_.stubTrue, () => "Hot"]
]);

console.log(getTemperatureLabel(-3));  // "Freezing"
console.log(getTemperatureLabel(5));   // "Cold"
console.log(getTemperatureLabel(20));  // "Moderate"
console.log(getTemperatureLabel(30));  // "Hot"

How It Works

Each predicate defines the upper bound of a band. Ordered ranges make the table easy to extend—insert a new pair without rewriting nested if blocks.

Example 5 — Edge cases with named predicates

Extract predicates for null, NaN, and fallback—keeps the pair list readable and unit-testable.

javascript
const describeValue = _.cond([
  [_.isNil,  () => "Missing value"],
  [_.isNaN,  () => "Not a number"],
  [_.isString, (v) => "String: " + v],
  [_.isNumber, (v) => "Number: " + v],
  [_.stubTrue, (v) => "Other: " + typeof v]
]);

console.log(describeValue(null));       // "Missing value"
console.log(describeValue(NaN));        // "Not a number"
console.log(describeValue("hello"));    // "String: hello"
console.log(describeValue(true));       // "Other: boolean"

How It Works

Lodash lang helpers like _.isNil and _.isNaN slot directly into predicate slots. Test null/NaN before generic type checks.

🚀 Beyond the Basics

Compare with imperative branching and know when each style fits.

Example 6 — cond vs switch statement

Same routing logic two ways—pick the one your team reads faster.

javascript
// Lodash cond — good for ranges and predicates
const condLabel = _.cond([
  [(n) => n < 0, () => "negative"],
  [(n) => n === 0, () => "zero"],
  [_.stubTrue, () => "positive"]
]);

// switch — good for exact discrete values
function switchLabel(code) {
  switch (code) {
    case "draft":   return "Draft";
    case "review":  return "In review";
    case "live":    return "Published";
    default:        return "Unknown";
  }
}

console.log(condLabel(-2));        // "negative"
console.log(switchLabel("live"));  // "Published"

When to prefer cond

Use _.cond() when rules are predicate-based (ranges, types, composite checks) and you want a composable function. Use switch for enum-like string/number constants.

🧠 How _.cond() Works

1

Build pairs table

Lodash stores your [predicate, handler] array on the returned function closure.

Setup
2

Call cond function

You invoke the function later with real arguments (score, status code, etc.).

Invoke
3

Walk pairs in order

Each predicate runs with the call arguments until one returns truthy.

Match
=

Return handler result

The matched handler runs and its return value is the final result—or undefined if nothing matched.

📝 Notes

  • Order is critical—specific predicates must appear before general ones.
  • Always add [_.stubTrue, handler] when you need a guaranteed default branch.
  • Predicates and handlers receive identical arguments from the outer call.
  • Handlers may return undefined intentionally—that is still a valid match result.
  • _.cond() does not catch errors inside predicates or handlers—wrap risky code yourself.
  • Pair with _.stubTrue() and lang helpers like _.isNil for readable tables.

Conclusion

_.cond() turns branching rules into data: an ordered list of tests and outcomes you can name, reuse, and pass like any other function. It shines for range categorizers, status routers, and type-driven formatters.

Keep tables short, order predicates carefully, and end with _.stubTrue when every input should resolve. For simple two-way logic, a ternary or if/else may still be the clearest choice.

💡 Best Practices

✅ Do

  • Put narrow, specific predicates before broad ones
  • End with [_.stubTrue, defaultHandler] when inputs vary widely
  • Extract complex predicates into named, testable functions
  • Reuse cond functions across modules as pure routers
  • Document pair order in a comment when rules overlap

❌ Don’t

  • Assume the last pair runs without a matching predicate—it will not
  • Build ten-branch cond tables when switch or if/else reads cleaner
  • Put value > 0 before value === 0 if zero needs its own branch
  • Forget that no match returns undefined
  • Throw inside predicates—return boolean results instead

Key Takeaways

Knowledge Unlocked

Five things to remember about _.cond()

Use these points when building functional conditionals.

5
Core concepts
👆 02

First match

Order matters.

Critical
03

stubTrue

Default else branch.

Pattern
📦 04

Same args

Shared call signature.

API
🔀 05

conforms

Next util helper.

Next step

❓ Frequently Asked Questions

_.cond() takes an array of [predicate, function] pairs and returns a new function. When you call that function, Lodash runs each predicate in order; the first one that returns a truthy value triggers its paired function, and that function's return value becomes the result.
Both the predicate and the matched handler receive the same arguments passed to the cond function. If you call getSize(15), every predicate and the chosen handler see 15 as their first argument.
_.stubTrue always returns true, so it acts as a default branch—like the final else in an if/else chain or default in a switch. Without it, no matching predicate returns undefined.
Yes. Lodash stops at the first matching predicate. Put more specific conditions before general ones, or a broad check like value > 0 will match before a narrower rule you intended to run first.
switch compares one value to case labels. _.cond() runs arbitrary predicate functions on the full argument list, which fits range checks, type guards, and object shape tests in a functional style.
Skip it for simple two-branch logic where a ternary or if/else is clearer, or when teammates are unfamiliar with functional patterns. Long cond tables can be harder to debug than explicit switch statements.
Did you know?

_.cond() is inspired by Ramda’s cond and Clojure’s cond macro. Lodash ships _.stubTrue specifically as an always-true predicate so your final pair behaves like a default clause without hard-coding () => true everywhere.

Practice _.cond() in the Live Editor

Open the Try It editor, run the examples, and experiment with your own predicate tables.

Open Try It editor →

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