Skip to documentation

guide

Migrate deepmerge: arrays, cycles and compatibility

Choose alias or direct imports and test object merging, arrays, cycles and intentional differences.

By Alexandro · Updated 2026-11-06

Decide what must remain compatible

This guide consolidates the existing adoption and compatibility notes for @stackline/deepmerge 1.1.2. Start with representative application fixtures rather than a global dependency override. The baseline used here is deepmerge 4.3.1; this is a behavior comparison, not a claim that every input is interchangeable.

Install by alias or direct import

For an application that already imports deepmerge:

npm install --save-exact deepmerge@npm:@stackline/[email protected]
npm ls deepmerge
npm test

Existing import merge from 'deepmerge' and require('deepmerge') calls retain their package name. For a new integration:

npm install --save-exact @stackline/[email protected]
import merge from '@stackline/deepmerge';
const config = merge({features:['read']}, {features:['write']});
// {features:['read','write']}

An alias changes dependency resolution; it does not automatically replace every transitive dependency. Review the lockfile and the parent package's compatibility requirements before using overrides.

Arrays, objects and deliberate differences

Default arrays concatenate. If a configuration array should replace its previous value, supply arrayMerge: (_target, source) => source. That callback returns the source array itself: choose a cloning policy explicitly when later mutations matter.

Circular references are preserved by the Stackline implementation; the upstream baseline overflows for the circular fixture below. The fork also drops own __proto__ keys. Getter behavior, custom callbacks, class instances, symbols, Map/Set and reference identity need application-specific assertions. Optional strict limits and advanced array strategies change behavior; enable them deliberately, following the versioned reference.

The reference discusses CVE-2026-93753. Our test below establishes only the specified own-key and cycle regressions; it does not certify absence of other vulnerabilities. Review the CVE record and your own trust boundaries before accepting untrusted objects.

Reproduce the migration checks

Requirements: Node.js with ESM support and the two pinned packages. The site repository contains scripts/docs/examples/package-lock.json; run npm ci --prefix scripts/docs/examples and npm test --prefix scripts/docs/examples. The following is the actual executed source, not a second copy of the example:

import assert from 'node:assert/strict';
import merge from '@stackline/deepmerge';
import upstream from 'deepmerge';
const fixtures = [
  [{roles:['reader'], nested:{a:1}}, {roles:['writer'], nested:{b:2}}],
  [{enabled:true, n:null}, {enabled:false, n:3}],
  [{x:[{id:1}]}, {x:[{id:2}]}]
];
for (const [target, source] of fixtures) {
  assert.deepEqual(merge(target, source), upstream(target, source));
}
const replace = {arrayMerge: (_target, source) => source};
assert.deepEqual(merge({roles:['reader']},{roles:['writer']},replace),{roles:['writer']});
const circular = {label:'root'};
circular.self = circular;
const result = merge({}, circular);
assert.equal(result.self, result);
assert.throws(() => upstream({}, circular), RangeError);
const hostile = JSON.parse('{"__proto__":{"polluted":true}}');
assert.equal(Object.hasOwn(merge({}, hostile), '__proto__'), false);
assert.equal({}.polluted, undefined);
console.log('deepmerge: ordinary fixtures, array replacement, cycle and own-key regression passed');

Expected: the ordinary fixtures match; array replacement is explicit; the cycle and own-key checks pass. Extend the fixture array with your configuration objects, serialization behavior and callback side effects. Run your application's full suite and production build before releasing.

Roll back and attribute the fork

Keep the previous lockfile and dependency declaration in version control. A rollback restores both, then uses npm ci. The original deepmerge project and license remain attributed in the fork repository. Consult its compatibility notes for intentional departures; a successful small fixture suite does not prove equivalence for an entire application.

Package installation and API reference · All guides