Which is Better JavaScript Object Merging Libraries?
deepmerge vs lodash.merge vs merge-deep vs deep-assign vs object-assign-deep
1 Year
deepmergelodash.mergemerge-deepdeep-assignobject-assign-deepSimilar Packages:
What's JavaScript Object Merging Libraries?

These libraries are designed to facilitate the merging of JavaScript objects, allowing developers to combine properties from multiple sources into a single target object. They provide various strategies for handling conflicts, deep merging, and immutability, which can be crucial in applications that require state management or configuration management. Understanding the nuances of each library can help developers choose the right tool for their specific use case, whether it's for simple object merging or more complex scenarios involving nested structures.

NPM Package Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
deepmerge34,556,1712,75631.2 kB542 years agoMIT
lodash.merge32,935,37559,716-1085 years agoMIT
merge-deep1,057,053111-134 years agoMIT
deep-assign192,195247-06 years agoMIT
object-assign-deep34,55370-97 years agoMIT
Feature Comparison: deepmerge vs lodash.merge vs merge-deep vs deep-assign vs object-assign-deep

Merging Strategy

  • deepmerge: deepmerge allows for customizable merging strategies, including handling arrays and providing options for conflict resolution, making it versatile for complex data structures.
  • lodash.merge: lodash.merge performs a deep merge but does not merge arrays, instead it replaces them. It is best suited for scenarios where you want to combine objects without altering array contents.
  • merge-deep: merge-deep offers a straightforward deep merging strategy that is easy to use, focusing on simplicity and clarity in the merging process without additional features.
  • deep-assign: deep-assign performs a simple deep merge, copying properties from source objects to the target object, but does not handle array merging or conflict resolution.
  • object-assign-deep: object-assign-deep extends the native Object.assign method to support deep merging, making it a lightweight option for projects that want to keep dependencies minimal.

Performance

  • deepmerge: deepmerge may have a slight performance overhead due to its customizable merging strategies, but it is efficient for complex object structures.
  • lodash.merge: lodash.merge is well-optimized and performs efficiently, especially in applications that already utilize lodash, benefiting from its overall performance enhancements.
  • merge-deep: merge-deep is designed for simplicity and speed, ensuring that deep merging operations are performed quickly without unnecessary complexity.
  • deep-assign: deep-assign is lightweight and optimized for performance, making it suitable for applications where speed is critical and deep merging is required without overhead.
  • object-assign-deep: object-assign-deep is lightweight and fast, making it an excellent choice for performance-sensitive applications that require deep merging.

Ease of Use

  • deepmerge: deepmerge provides a more complex API due to its customizable options, which may require a bit more learning but offers greater flexibility for advanced use cases.
  • lodash.merge: lodash.merge is part of the lodash library, which is widely used and well-documented, making it easy to integrate and use for those familiar with lodash.
  • merge-deep: merge-deep has a simple and intuitive API, making it easy for developers to implement deep merging without extensive documentation.
  • deep-assign: deep-assign has a straightforward API that is easy to understand, making it accessible for developers who need quick and simple object merging.
  • object-assign-deep: object-assign-deep is easy to use, especially for those familiar with Object.assign, providing a familiar interface for deep merging.

Conflict Resolution

  • deepmerge: deepmerge excels in conflict resolution, allowing developers to define how conflicts should be handled, making it ideal for complex merging scenarios.
  • lodash.merge: lodash.merge replaces properties in the target object with those from source objects without any conflict resolution, which may lead to data loss if not managed carefully.
  • merge-deep: merge-deep does not offer advanced conflict resolution features, focusing instead on straightforward merging without additional complexity.
  • deep-assign: deep-assign does not provide built-in conflict resolution; it simply overwrites properties in the target object with those from source objects, which may not be suitable for all scenarios.
  • object-assign-deep: object-assign-deep overwrites properties in the target object with those from source objects, similar to Object.assign, without advanced conflict resolution.

Dependency Size

  • deepmerge: deepmerge is relatively lightweight but has more features, which may increase the size slightly compared to simpler libraries.
  • lodash.merge: lodash.merge is part of the larger lodash library, which can increase the overall size of your dependencies if only this function is needed.
  • merge-deep: merge-deep is lightweight and focused, making it a good choice for projects that want to keep their dependency size minimal.
  • deep-assign: deep-assign is a minimal library with a small footprint, making it ideal for projects that prioritize reducing dependency size.
  • object-assign-deep: object-assign-deep is very lightweight, making it an excellent choice for projects that want to avoid bloating their dependency tree.
How to Choose: deepmerge vs lodash.merge vs merge-deep vs deep-assign vs object-assign-deep
  • deepmerge: Opt for deepmerge if you require a robust solution that handles arrays and provides a customizable merging strategy. It's particularly useful in scenarios where you need to merge complex nested objects and want to control how conflicts are resolved.
  • lodash.merge: Select lodash.merge if you are already using lodash in your project and prefer a comprehensive utility library. It offers a well-tested and reliable merging function, but keep in mind it does not perform deep merging for arrays, which may be a limitation in some cases.
  • merge-deep: Use merge-deep if you need a library that focuses on deep merging with a simple API. It's a good choice for projects that prioritize ease of use and clarity in merging operations without the overhead of additional features.
  • deep-assign: Choose deep-assign if you need a simple and straightforward solution for deep merging objects without any additional features. It's lightweight and ideal for basic use cases where performance is a concern.
  • object-assign-deep: Consider object-assign-deep if you are looking for a lightweight solution that extends the native Object.assign method to support deep merging. This is suitable for projects that want to keep dependencies minimal while still achieving deep merge functionality.
README for deepmerge

deepmerge

Merges the enumerable properties of two or more objects deeply.

UMD bundle is 723B minified+gzipped

Getting Started

Example Usage

const x = {
	foo: { bar: 3 },
	array: [{
		does: 'work',
		too: [ 1, 2, 3 ]
	}]
}

const y = {
	foo: { baz: 4 },
	quux: 5,
	array: [{
		does: 'work',
		too: [ 4, 5, 6 ]
	}, {
		really: 'yes'
	}]
}

const output = {
	foo: {
		bar: 3,
		baz: 4
	},
	array: [{
		does: 'work',
		too: [ 1, 2, 3 ]
	}, {
		does: 'work',
		too: [ 4, 5, 6 ]
	}, {
		really: 'yes'
	}],
	quux: 5
}

merge(x, y) // => output

Installation

With npm do:

npm install deepmerge

deepmerge can be used directly in the browser without the use of package managers/bundlers as well: UMD version from unpkg.com.

Include

deepmerge exposes a CommonJS entry point:

const merge = require('deepmerge')

The ESM entry point was dropped due to a Webpack bug.

API

merge(x, y, [options])

Merge two objects x and y deeply, returning a new merged object with the elements from both x and y.

If an element at the same key is present for both x and y, the value from y will appear in the result.

Merging creates a new object, so that neither x or y is modified.

Note: By default, arrays are merged by concatenating them.

merge.all(arrayOfObjects, [options])

Merges any number of objects into a single result object.

const foobar = { foo: { bar: 3 } }
const foobaz = { foo: { baz: 4 } }
const bar = { bar: 'yay!' }

merge.all([ foobar, foobaz, bar ]) // => { foo: { bar: 3, baz: 4 }, bar: 'yay!' }

Options

arrayMerge

There are multiple ways to merge two arrays, below are a few examples but you can also create your own custom function.

Your arrayMerge function will be called with three arguments: a target array, the source array, and an options object with these properties:

  • isMergeableObject(value)
  • cloneUnlessOtherwiseSpecified(value, options)

arrayMerge example: overwrite target array

Overwrites the existing array values completely rather than concatenating them:

const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray

merge(
	[1, 2, 3],
	[3, 2, 1],
	{ arrayMerge: overwriteMerge }
) // => [3, 2, 1]

arrayMerge example: combine arrays

Combines objects at the same index in the two arrays.

This was the default array merging algorithm pre-version-2.0.0.

const combineMerge = (target, source, options) => {
	const destination = target.slice()

	source.forEach((item, index) => {
		if (typeof destination[index] === 'undefined') {
			destination[index] = options.cloneUnlessOtherwiseSpecified(item, options)
		} else if (options.isMergeableObject(item)) {
			destination[index] = merge(target[index], item, options)
		} else if (target.indexOf(item) === -1) {
			destination.push(item)
		}
	})
	return destination
}

merge(
	[{ a: true }],
	[{ b: true }, 'ah yup'],
	{ arrayMerge: combineMerge }
) // => [{ a: true, b: true }, 'ah yup']

isMergeableObject

By default, deepmerge clones every property from almost every kind of object.

You may not want this, if your objects are of special types, and you want to copy the whole object instead of just copying its properties.

You can accomplish this by passing in a function for the isMergeableObject option.

If you only want to clone properties of plain objects, and ignore all "special" kinds of instantiated objects, you probably want to drop in is-plain-object.

const { isPlainObject } = require('is-plain-object')

function SuperSpecial() {
	this.special = 'oh yeah man totally'
}

const instantiatedSpecialObject = new SuperSpecial()

const target = {
	someProperty: {
		cool: 'oh for sure'
	}
}

const source = {
	someProperty: instantiatedSpecialObject
}

const defaultOutput = merge(target, source)

defaultOutput.someProperty.cool // => 'oh for sure'
defaultOutput.someProperty.special // => 'oh yeah man totally'
defaultOutput.someProperty instanceof SuperSpecial // => false

const customMergeOutput = merge(target, source, {
	isMergeableObject: isPlainObject
})

customMergeOutput.someProperty.cool // => undefined
customMergeOutput.someProperty.special // => 'oh yeah man totally'
customMergeOutput.someProperty instanceof SuperSpecial // => true

customMerge

Specifies a function which can be used to override the default merge behavior for a property, based on the property name.

The customMerge function will be passed the key for each property, and should return the function which should be used to merge the values for that property.

It may also return undefined, in which case the default merge behaviour will be used.

const alex = {
	name: {
		first: 'Alex',
		last: 'Alexson'
	},
	pets: ['Cat', 'Parrot']
}

const tony = {
	name: {
		first: 'Tony',
		last: 'Tonison'
	},
	pets: ['Dog']
}

const mergeNames = (nameA, nameB) => `${nameA.first} and ${nameB.first}`

const options = {
	customMerge: (key) => {
		if (key === 'name') {
			return mergeNames
		}
	}
}

const result = merge(alex, tony, options)

result.name // => 'Alex and Tony'
result.pets // => ['Cat', 'Parrot', 'Dog']

clone

Deprecated.

Defaults to true.

If clone is false then child objects will be copied directly instead of being cloned. This was the default behavior before version 2.x.

Testing

With npm do:

npm test

License

MIT