How to Merge Objects in JavaScript
Merge two or more objects with the spread operator or Object.assign(), understand how key conflicts resolve, and know why both do a shallow merge.
Overview
To combine the properties of several objects into one, JavaScript gives you two tools: the spread operator { ...a, ...b } and Object.assign(). Spread is the modern default because it always produces a new object; Object.assign() is the older method and can either build a new object or write into an existing one. Both do a shallow merge, and both resolve key conflicts the same way — the last object wins.
Steps
1. Merge with the spread operator
Spreading each object into a new literal copies all their own enumerable properties into one fresh object. This is the cleanest way to merge because it never touches the sources — you always get a brand-new object back.
const a = { a: 1 };
const b = { b: 2 };
const merged = { ...a, ...b };
console.log(merged); // { a: 1, b: 2 }
2. Understand how conflicts resolve
When two objects have the same key, the later one in the spread order overwrites the earlier. This is what makes spread perfect for applying overrides or defaults: list the defaults first and the overrides last.
const defaults = { theme: 'light', size: 'md' };
const prefs = { theme: 'dark' };
console.log({ ...defaults, ...prefs });
// { theme: 'dark', size: 'md' } — prefs override defaults
3. Merge with Object.assign()
Object.assign(target, ...sources) copies the sources into target and returns it. Pass a fresh {} as the target to build a new object without mutating anything — always do this unless you specifically intend to modify the target in place.
const a = { a: 1 };
const b = { b: 2 };
const merged = Object.assign({}, a, b);
console.log(merged); // { a: 1, b: 2 }
console.log(a); // { a: 1 } — untouched, thanks to the {} target
In practice, prefer spread for its clarity and immutability, and reach for Object.assign() only when you must write into an existing object — updating a config in place, say — or when merging a variable number of sources you already hold in an array, where Object.assign({}, ...list) reads more naturally than repeated spreads. The two produce identical results for the same inputs; the choice is about mutation and style, not behavior.
One more nuance: merging preserves the key order you'd expect. Keys from earlier objects keep their position, a later object that overrides a key updates the value without moving it, and genuinely new keys are appended at the end. That stability matters whenever the object's order is visible — a rendered form, a serialised JSON payload, a set of columns.
Runnable example
The complete, runnable version — edit the objects and watch conflicts resolve:
Common pitfalls
Both approaches copy only own enumerable properties, and both trigger setter functions on the target — edge cases you rarely hit with plain data objects, but worth knowing exist when merging class instances.
Frequently asked questions
What's the easiest way to merge two objects in JavaScript?
const merged = { ...a, ...b }. It returns a new object and, on key conflicts, keeps the value from the rightmost object.Which value wins when merged objects share a key?
{ ...a, ...b } and Object.assign({}, a, b), b's value overwrites a's for any shared key.Does merging objects modify the originals?
Object.assign(target, ...) mutates the target, so pass a fresh {} as the target to avoid changing your input objects.