Lodash _.defaultsDeep() Method

Beginner
5 min read
Updated: Nov 2026
5 examples
Object

Definition

Recursively assigns source properties to the destination for leaves that are still undefined. Plain objects and arrays are walked; defined values win. Since Lodash 3.10.0.

Pass the object and path or keys shown below. Check whether the helper mutates or returns a new object.

Syntax

Call _.defaultsDeep. Start with this line.

Lodash
_.defaultsDeep(object, ...sources)
CallWhat it does
_.defaultsDeep(object, ...sources)Primary signature.
_.defaultsDeep(object)Work with an object’s keys, values, or paths.

Prefer import defaultsDeep from "lodash/defaultsDeep" when you want a smaller bundle.

Library declarations
Lodash
_.defaultsDeep(object, ...sources)

Parameters

ParameterDescription
objectRequired. Destination (mutated and returned)
...sourcesOptional. Default providers (left → right)

Return Value

Return ValueDescription
*The value returned by _.defaultsDeep().

Lodash Examples

Example 1 — Official: Keep Defined, Fill Missing Leaves

Existing nested values win; new leaves come from sources.

Lodash
_.defaultsDeep({ a: { b: 2 } }, { a: { b: 1, c: 3 } });
// → { a: { b: 2, c: 3 } }
Try It Yourself

How It Works

  1. Destination already has a.b = 2.
  2. Recurse into matching plain object a.
  3. b stays 2; source 1 is ignored.
  4. c was missing → filled with 3.

Example 2 — vs _.defaults

A defined nested object stops shallow defaults; deep walk fills inside.

Lodash
var base = { user: { name: "Guest" } };
var fill = { user: { name: "Admin", role: "viewer" } };

_.defaults(_.cloneDeep(base), fill);
// → { user: { name: "Guest" } }

_.defaultsDeep(_.cloneDeep(base), fill);
// → { user: { name: "Guest", role: "viewer" } }
Try It Yourself

How It Works

  1. defaults. user is already an object → whole branch kept.
  2. defaultsDeep. Walks into user.
  3. name stays "Guest"; role is filled.
  4. Pick deep when nested option bags need gap-filling.

Example 3 — Arrays Merged by Index

Arrays are not opaque — each index is compared like a leaf.

Lodash
_.defaultsDeep({ tags: ["a", "b"] }, { tags: ["x", "y", "z"] });
// → { tags: ["a", "b", "z"] }

_.defaultsDeep({ tags: undefined }, { tags: ["x", "y", "z"] });
// → { tags: ["x", "y", "z"] }
Try It Yourself

How It Works

  1. Indexes 0 and 1 are defined → keep "a", "b".
  2. Index 2 is missing → filled with "z".
  3. undefined tags → whole array copied from the source.
  4. Tip. Expect positional merge, not wholesale replace.

Example 4 — null vs undefined

Only undefined leaves are treated as gaps.

Lodash
_.defaultsDeep(
  { a: { b: null, c: undefined } },
  { a: { b: 1, c: 2, d: 3 } }
);
// → { a: { b: null, c: 2, d: 3 } }
Try It Yourself

How It Works

  1. b is null → kept (not a gap).
  2. c is undefined → filled with 2.
  3. d is missing → filled with 3.
  4. Tip. Normalize null first if you want it replaced too.

Example 5 — vs _.merge (Safe {} Pattern)

defaultsDeep keeps destination leaves; merge lets sources overwrite.

Lodash
var user = { a: { b: 2 } };
var src  = { a: { b: 1, c: 3 } };

_.defaultsDeep({}, user, src);
// → { a: { b: 2, c: 3 } }

_.merge({}, user, src);
// → { a: { b: 1, c: 3 } }
Try It Yourself

How It Works

  1. {} avoids mutating user.
  2. defaultsDeep. User b: 2 wins; c is filled.
  3. merge. Later source overwrites b to 1.
  4. Pick defaultsDeep for “keep my config, fill the rest.”

Browser & Runtime Support

_.defaultsDeep is a Lodash Object helper (since 3.10.0). It runs anywhere Lodash 4.x runs — modern browsers (CDN or bundle) and Node.js / Bun / Deno with npm install lodash.

✓ Stable · Lodash 3.10.0+

_.defaultsDeep()

Available in [email protected] full builds and the lodash/defaultsDeep modular import. Works in evergreen browsers and current Node LTS when Lodash is installed.

100% With Lodash 4.x
Google Chrome Supported · Desktop & Mobile
Full support
Mozilla Firefox Supported · Desktop & Mobile
Full support
Apple Safari Supported · macOS & iOS
Full support
Microsoft Edge Supported · Chromium
Full support
Internet Explorer No native support · Use a polyfill
Polyfill
Opera Supported · Modern versions
Full support
Samsung Internet Supported · Android
Full support
Bun Supported · JavaScript runtime
Supported
Deno Supported · JavaScript runtime
Supported
Node.js Supported · Server runtime
Supported
Android WebView Supported · Modern WebView
Full support
_.defaultsDeep Lodash 3.10.0+

Bottom line: Safe for production once Lodash is loaded. Prefer import defaultsDeep from "lodash/defaultsDeep". Use shallow _.defaults when nesting is not needed.

Frequently Asked Questions

_.defaultsDeep(object, ...sources) recursively assigns source properties to the destination only where the destination value is undefined. Plain objects and arrays are walked; defined leaves are left alone.
_.defaults is shallow: a defined nested object blocks everything under it. _.defaultsDeep recurses so each undefined leaf can still be filled.
_.merge overwrites — source leaves win. _.defaultsDeep never overwrites a defined destination leaf.
No. Only undefined counts as missing. null at a leaf is kept.
No. Arrays are merged by index. Defined indexes stay; longer source arrays can fill later indexes.
Yes. Pass {} when you need a fresh object: _.defaultsDeep({}, userCfg, defaults).

Next: _.findKey()

Return the first own key whose value matches a predicate.

_.findKey() tutorial →

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.

11 people found this page helpful