How Lodash _.merge Prioritizes Nested Arrays

Lodash’s _.merge method recursively combines properties from source objects into a destination object, but its handling of nested arrays often surprises developers. Unlike shallow copy operations or other deep-merging tools that overwrite or concatenate lists, _.merge treats arrays as index-keyed objects. This article breaks down how _.merge processes explicit nested arrays, demonstrating its index-by-index priority mechanism and how it differs from traditional object property resolution.

The Index-Based Merging Strategy

When _.merge encounters an array at a matching key in both the target and source objects, it does not replace the target array, nor does it append the new elements. Instead, it iterates through the indices of the source array and merges each element into the corresponding index of the target array.

Because arrays in JavaScript are internally objects with numerical keys, _.merge treats an array like { '0': val1, '1': val2 }.

const target = { items: [1, 2, 3] };
const source = { items: [9, 8] };

_.merge(target, source);
// Result: { items: [9, 8, 3] }

In this example:

Nested Objects Inside Arrays

The recursive nature of _.merge becomes most apparent when nested arrays contain objects. Rather than replacing the object at a given index, Lodash deeply merges the source object into the target object residing at that same position.

const target = {
  users: [
    { id: 1, name: "Alice", role: "User" },
    { id: 2, name: "Bob" }
  ]
};

const source = {
  users: [
    { role: "Admin" },
    { name: "Robert", role: "Moderator" },
    { id: 3, name: "Charlie" }
  ]
};

_.merge(target, source);

The resulting target.users evaluates to:

[
  { id: 1, name: "Alice", role: "Admin" },
  { id: 2, name: "Robert", role: "Moderator" },
  { id: 3, name: "Charlie" }
]

At index 0, role is updated while id and name are preserved. At index 1, name is overwritten and role is added. At index 2, a new element is appended because the target did not have an existing entry at that index.

Type Mismatches: Array vs. Non-Array

When a key conflicts across source and destination with mismatched data types, _.merge prioritizes the source value:

const target = { data: [1, 2, 3] };
const source = { data: "reset" };

_.merge(target, source);
// Result: { data: "reset" }

Customizing Array Merging with _.mergeWith

Because index-based mutation is often not the desired behavior for arrays—concatenation or complete replacement is frequently preferred—Lodash provides _.mergeWith. This method accepts a customizer function to bypass the default array-merging logic:

function customizer(objValue, srcValue) {
  if (_.isArray(objValue)) {
    return objValue.concat(srcValue); // Concatenate instead of merging by index
  }
}

const target = { tags: ["javascript"] };
const source = { tags: ["react"] };

_.mergeWith(target, source, customizer);
// Result: { tags: ["javascript", "react"] }

Returning undefined from the customizer falls back to the default _.merge behavior, allowing fine-grained control over specific keys while keeping index-based merging intact for others.