Lodash _.setWith() Method

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

What You’ll Learn

By the end of this tutorial, you’ll use _.setWith() to control how nested paths are built when plain _.set() is not enough.

01

Core syntax

_.setWith(object, path, value, customizer)

02

Customizer role

Builds intermediate containers, not the leaf value.

03

Object / Array

Pass constructors for predictable nested shapes.

04

vs _.set()

When defaults are fine vs when you need control.

05

undefined fallback

Return undefined to use Lodash defaults.

06

Real patterns

Array-heavy paths, dynamic builders, updates.

What Is _.setWith()?

_.setWith() is like _.set() with an extra hook: a customizer function that decides what kind of container to create when Lodash needs a missing intermediate step along the path. The final value you pass is still assigned directly at the leaf—the customizer does not transform it.

💡
Customizer builds the path, not the value

Think of _.setWith() as “set, but let me choose whether the next missing segment is an array, a plain object, or something custom.”

Reach for it when you need explicit Array or Object constructors, custom container types, or fine-grained control over nested structure—especially for array-heavy paths like a[0].b.c.

📝 Syntax

The signature adds an optional fourth argument—the customizer:

javascript
_.setWith(object, path, value, [customizer])

Syntax Rules

  • object — target object (mutated in place).
  • path — same formats as _.set: dot string, brackets, or key array.
  • value — assigned at the final path segment.
  • customizer — optional (nsValue, key, object) => container; called when a missing intermediate container is needed.
  • Return value — the same object reference.
javascript
import setWith from "lodash/setWith";

const object = {};
setWith(object, "a[0].b.c", 42, Object);

// object -> { a: [{ b: { c: 42 } }] }

⚡ Quick Reference

TaskCode patternResult
Plain nested set_.setWith(obj, "a.b", 1)Same defaults as _.set
Force plain objects_.setWith(obj, path, val, Object)Object constructor as customizer
Array-heavy path_.setWith(obj, "[0][1]", 3, Array)Array constructor for slots
Custom logic_.setWith(obj, path, val, (v, k) => ...)Pick [] vs {} per key
Default fallbackreturn undefined in customizerLodash uses built-in rules
No customizer needed_.set(obj, path, val)Use _.set()
Customizer
Intermediates

Not the leaf value

Mutates?
Yes

Like _.set()

undefined
Fallback

Default containers

Pair with
_.set()

Simpler default writes

🧰 Parameters

Arguments to _.setWith() and how the customizer fits in:

object Required

The object to modify. Lodash walks or creates the path inside this object and returns the same reference.

const state = {};
_.setWith(state, "ui.theme", "dark")
path Required

Nested location: dot string, bracket notation, or array of keys—identical to _.set.

_.setWith(o, "a[0].b.c", 42, Object)
value Required

The value written at the final segment. Assigned directly; the customizer does not modify it.

_.setWith(o, "score", 99, Object)
customizer Optional

(nsValue, key, object) => container. Creates missing intermediate objects or arrays. Return undefined for Lodash defaults.

(nsValue, key) =>
  String(+key) === key ? [] : {}

Passing Object or Array as the customizer works because Lodash invokes them with new to construct containers—a common shorthand in Lodash docs.

Examples Gallery

Practical _.setWith() patterns with sample output and interactive Try It Yourself labs.

📚 Getting Started

Set deeply nested paths with explicit container constructors.

Example 1 — Deep path with Object customizer

Set a[0].b.c on an empty object using Object to build intermediate containers.

javascript
const object = {};

_.setWith(object, "a[0].b.c", 42, Object);

console.log(object);
// -> { a: [{ b: { c: 42 } }] }
Try It Yourself

How It Works

Lodash creates a, then index 0, then b, using the customizer when each segment is missing.

Example 2 — Array constructor for nested indices

Official Lodash pattern: pass Array when the path is index-heavy.

javascript
const object = {};

_.setWith(object, "[0][1][2]", 3, Array);

console.log(object[0][1][2]);
// -> 3
Try It Yourself

Sparse arrays may show empty slots before the assigned index—that is expected when building deep array paths.

📈 Practical Patterns

Custom container logic, updates, and reusable builders.

Example 3 — Custom customizer (array vs object)

Choose [] for numeric keys and {} for string keys when creating intermediates.

javascript
const object = {};

const customizer = (nsValue, key) => {
  if (nsValue !== undefined) return nsValue;
  return String(+key) === key ? [] : {};
};

_.setWith(object, "rows[0].cells[1]", "Hello", customizer);

console.log(object.rows[0].cells[1]);
// -> "Hello"
Try It Yourself

Example 4 — Update an existing nested value

When the path already exists, _.setWith overwrites the leaf value like _.set.

javascript
const object = { a: { b: { c: 42 } } };

_.setWith(object, "a.b.c", 99, Object);

console.log(object.a.b.c);
// -> 99

Example 5 — Reusable nested-object builder

Wrap _.setWith in a helper for dynamic path assignment.

javascript
function createNested(path, value) {
  const object = {};
  _.setWith(object, path, value, Object);
  return object;
}

const nested = createNested("config.api.timeout", 5000);

console.log(nested);
// -> { config: { api: { timeout: 5000 } } }

🚀 Beyond the Basics

When to prefer _.setWith over plain _.set.

Example 6 — When _.set() is enough

For simple dot paths, _.set() already creates intermediates—use _.setWith only when you need custom container logic.

javascript
const a = {};
const b = {};

_.set(a, "profile.name", "Ada");
_.setWith(b, "profile.name", "Ada", Object);

console.log(JSON.stringify(a) === JSON.stringify(b));
// -> true (same shape for simple object paths)

🧠 How _.setWith() Works

1

Parse path

Lodash splits the path into segments, same as _.set.

Input
2

Customizer creates containers

When a segment is missing, the customizer runs to produce the next object or array. Return undefined for defaults.

Build
3

Assign leaf value

The final segment receives your value argument directly—no customizer on the leaf.

Write
=

Path written

The same object reference is returned, now containing the nested value with your custom container rules.

📝 Notes

  • The customizer builds intermediate containers only—it does not transform the leaf value.
  • Return undefined from the customizer to fall back to Lodash defaults (same as _.set).
  • _.setWith mutates the target object like _.set.
  • Passing Object or Array as the customizer is a common shorthand for container creation.
  • For simple dot paths without special container rules, _.set() is usually enough.
  • Do not confuse the setWith customizer with mergeWith merge rules—they solve different problems.

Conclusion

_.setWith() extends _.set() with a customizer hook for building intermediate containers along a path. Use it when array/object constructor control matters; reach for plain _.set when default behavior is fine.

Remember: the customizer shapes the path, not the leaf value. For merge-time customization, see _.mergeWith(). Next up in the object series: _.toPairs().

💡 Best Practices

✅ Do

  • Use _.setWith when you need explicit Array or Object containers
  • Return existing nsValue from the customizer when reusing containers
  • Return undefined when Lodash defaults are correct
  • Prefer _.set for simple profile/config paths
  • Clone first when immutability is required

❌ Don’t

  • Expect the customizer to double or format the final value (old tutorials often get this wrong)
  • Wrap setWith in try/catch for normal path writes—it rarely throws
  • Reach for setWith when _.set already produces the shape you need
  • Confuse setWith customizer with mergeWith merge rules
  • Forget that setWith still mutates the target object

Key Takeaways

Knowledge Unlocked

Five things to remember about _.setWith()

Use these when nested paths need custom container logic.

5
Core concepts
📦 02

Leaf value

Assigned as-is.

Important
🗃️ 03

Object / Array

Constructor shorthand.

Pattern
🔀 04

vs _.set

Defaults vs control.

Compare
⚠️ 05

Mutates

Like _.set().

Note

❓ Frequently Asked Questions

_.setWith() writes a value at a nested path like _.set(), but lets you pass a customizer that decides how missing intermediate containers (objects or arrays) are created along the path.
_.set() always creates plain {} objects or array slots with default rules. _.setWith() adds an optional customizer so you can force Array, Object, Map, or custom logic when building the path.
The customizer is called as (nsValue, key, object). nsValue is the existing value at that segment (often undefined), key is the current path segment, and object is the parent being written into.
No. The customizer only creates intermediate containers while walking the path. The leaf value you pass as the third argument is assigned directly at the end.
Lodash falls back to its default: numeric index keys get arrays, other keys get plain objects—same behavior as _.set().
Yes. Like _.set(), it mutates the target object in place and returns the same reference.
Did you know?

Older tutorials sometimes show a customizer that “doubles” the final number at a.b.c—that is incorrect. The customizer only runs for missing intermediate segments; the leaf value 21 would stay 21, not become 42.

Practice _.setWith() in the Live Editor

Build nested array paths with Object and Array customizers and see results instantly.

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