Lodash _.defaults() method

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

What you’ll learn

  • How _.defaults(object, ...sources) fills only undefined keys on the destination—the opposite precedence of _.assign.
  • Why null counts as “already set” and is not replaced.
  • How to keep callers’ objects untouched by passing {} as the destination.
  • Try each example in the editor (?tryit=1, 2, 3) with Lodash from a CDN.

Prerequisites

Read _.assign() first—_.defaults uses the same shallow / mutating shape but flips the precedence rule.

  • undefined vs null: only undefined is treated as “missing”. Knowing the distinction prevents surprise no-ops.
  • Mutation awareness: the destination is written in place and returned—callers sharing the reference will see the new keys.

Overview

_.defaults walks each source left to right and writes a key onto the destination only when the destination’s current value is undefined. The original object always wins; among sources, the first one to define a key wins.

Original wins

User-supplied values are protected: _.defaults never overwrites an existing key.

First source wins

Among sources, the earliest one to define a key fills the gap—opposite of _.assign’s last-wins rule.

Shallow

Nested objects on the destination block all defaults below them—use _.defaultsDeep for recursion.

Syntax

javascript
_.defaults(object, [...sources])
  • object: destination; mutated in place.
  • sources: zero or more source objects walked left to right; only own enumerable string keys are considered.
  • Write rule: a key is written to object only when its current value is undefined.
  • Returns: the (now-mutated) destination object.
1

Fill in only the missing keys

The user’s theme survives because it’s already defined; language comes from the defaults object because the user didn’t supply one.

javascript
import defaults from "lodash/defaults";

const userSettings    = { username: "JohnDoe", theme: "light" };
const defaultSettings = { theme: "dark", language: "en" };

defaults(userSettings, defaultSettings);
// userSettings -> { username: "JohnDoe", theme: "light", language: "en" }
//                                          ^^^^^^^^^^^^   ^^^^^^^^^^^^^^
//                                          user wins      default fills
Try it Yourself
2

First source to define a key wins

Once a key is set on the destination, no later source can change it—the inverse of _.assign. Useful when you want a primary defaults bundle plus an optional fallback bundle.

javascript
import defaults from "lodash/defaults";

const user    = { a: 1 };
const primary = { b: 2,         c: 3 };
const fallback = { b: "ignored", c: "ignored", d: 4 };

defaults(user, primary, fallback);
// user -> { a: 1, b: 2, c: 3, d: 4 }
//                ^^^^^^^^^^^^   ^^^^^^^
//                primary wins   fallback only fills "d"
Try it Yourself
3

null counts as “already set”

Only literal undefined is replaced. A null on the destination blocks the default. Also note the “pass {} as the destination” pattern for keeping callers’ objects untouched.

javascript
import defaults from "lodash/defaults";

const userPrefs = { theme: null, lang: undefined };
const defs      = { theme: "light", lang: "en", fontSize: 14 };

const result = defaults({}, userPrefs, defs);
// result    -> { theme: null, lang: "en", fontSize: 14 }
//                ^^^^^^^^^^^   ^^^^^^^^^^   ^^^^^^^^^^^^^
//                null kept     undefined    no key at all
//                              replaced     -> filled by defs
console.log(userPrefs);
// { theme: null, lang: undefined }   (untouched)
Try it Yourself

📋 _.defaults vs _.assign vs _.defaultsDeep

Topic_.defaults_.assign_.defaultsDeep
PrecedenceDestination wins; first source fillsLast source wins (overwrites)Destination wins; first source fills
Replaces null?No—only undefinedYesNo—only undefined
DepthShallowShallowRecursive (plain objects & arrays)
Typical useFlat options + a fallback bundleLayer flat configsNested config trees

Reach for _.defaults when you want a no-overwrite merge of flat options; jump to _.defaultsDeep the moment your config nests plain objects.

Pitfalls to avoid

null

null blocks the default

Only undefined counts as missing. If a form clears a field to null, the default will not step in. Sanitize first or use _.defaults({}, ...) with a pre-clean.

Precedence

Confusing with _.assign

Old habits expect last-wins. _.defaults(target, primary, fallback) walks primary before fallback—exactly the opposite intuition.

Mutation

Destination is written in place

Pass {} as the first argument to leave the caller’s options object untouched—essential in shared-config or Redux-style code paths.

❓ FAQ

Opposite precedence. _.assign overwrites: later sources win. _.defaults fills gaps only: a key is written only when its current value on the destination is undefined, so the FIRST source to define it wins, and the original object always beats every source.
No. Only literal undefined is considered missing. null counts as 'already set' and the default will not overwrite it. If you also want null to be replaced, sanitize first or use a customizer with _.assignInWith.
Yes. The first argument is written in place and returned. Pass {} as the destination when you want a fresh object: const opts = _.defaults({}, userOpts, defaults).
Shallow. A defined nested object on the destination is left untouched, even if its own keys are undefined inside. Use _.defaultsDeep when you need recursive gap-filling on nested plain objects.
No. Like _.assign, only own enumerable string-keyed properties are considered on each source. Symbol keys and inherited keys are skipped.
Use import defaults from "lodash/defaults"; for ESM or const defaults = require('lodash/defaults') in CommonJS.

Summary

Did you know?

_.defaults reverses the precedence rule of _.assign. Sources are still walked left to right, but a key is only written when its current value is undefined—so the first source that defines a key wins, and the original object always beats every source.

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