Question
How to Merge JavaScript Objects: Object.assign, Spread Syntax, and Practical Patterns
Question
I need to merge two simple JavaScript objects at runtime. For example:
var obj1 = { food: 'pizza', car: 'ford' };
var obj2 = { animal: 'dog' };
// Desired result: obj1 should end up with food, car, and animal
Is there a built-in way to combine the properties of one object into another in JavaScript?
I do not need deep recursion, and I do not need to merge functions. I only need to work with flat objects and copy their properties.
Short Answer
By the end of this page, you will understand how to merge flat JavaScript objects using built-in tools such as Object.assign() and object spread syntax. You will also learn what happens when property names conflict, when the original object is mutated, and which approach is most common in modern JavaScript.
Concept
In JavaScript, objects store data as key-value pairs. Merging objects means taking the properties from one object and copying them into another object.
For flat objects, this is straightforward:
- Read the properties from a source object
- Copy them onto a target object
- If the same property exists in both, the later value usually replaces the earlier one
This matters because object merging is a very common task in real programs. Developers use it to:
- combine configuration settings
- update application state
- build API request options
- add default values to user input
JavaScript provides built-in ways to do this:
Object.assign()- object spread syntax:
{ ...obj1, ...obj2 }
These are ideal for shallow merges. A shallow merge means only the top-level properties are copied. If a property contains another object or array, the inner value is not deeply merged.
In your case, since the objects are simple and flat, a shallow merge is exactly what you need.
Mental Model
Think of each object as a small label sheet.
obj1has labels:food,carobj2has label:animal
Merging means taking the labels from the second sheet and placing them onto the first sheet.
If both sheets have the same label name, the new label covers the old one.
So object merging is like combining two sets of named fields into one final set.
Syntax and Examples
Using Object.assign()
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
Object.assign(obj1, obj2);
console.log(obj1);
// { food: 'pizza', car: 'ford', animal: 'dog' }
Object.assign(target, source) copies the enumerable properties from the source object into the target object.
obj1is the targetobj2is the sourceobj1is changed directly
Creating a new merged object
If you do not want to change the original object:
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const merged = Object.assign({}, obj1, obj2);
console.log(merged);
// { food: 'pizza', car: 'ford', animal: 'dog' }
console.log(obj1);
// { food: 'pizza', car: 'ford' }
Here, {} is the new target object.
Using spread syntax
Modern JavaScript often uses spread syntax because it is short and readable:
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const merged = { ...obj1, ...obj2 };
console.log(merged);
// { food: 'pizza', car: 'ford', animal: 'dog' }
What if both objects have the same property?
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { car: 'tesla', animal: 'dog' };
const merged = { ...obj1, ...obj2 };
console.log(merged);
// { food: 'pizza', car: 'tesla', animal: 'dog' }
The later object wins. Since obj2 comes after obj1, its car value replaces the old one.
Step by Step Execution
Consider this example:
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const merged = Object.assign({}, obj1, obj2);
Step by step:
-
const obj1 = ...- JavaScript creates an object with two properties:
food: 'pizza'car: 'ford'
-
const obj2 = ...- JavaScript creates another object with one property:
animal: 'dog'
-
Object.assign({}, obj1, obj2)- JavaScript starts with an empty object
{} - It copies properties from
obj1into it - The object becomes:
{ food: 'pizza', car: 'ford' }- Then it copies properties from
obj2 - The object becomes:
{ food: 'pizza', car: 'ford', animal: 'dog' } - JavaScript starts with an empty object
-
mergednow refers to the final combined object
Another trace with a conflict:
const a = { x: 1, y: 2 };
const b = { y: 99, z: 3 };
const result = { ...a, ...b };
Execution:
- Copy
x: 1,y: 2froma - Copy
y: 99,z: 3fromb yalready exists, so99replaces2- Final result:
{ x: 1, y: 99, z: 3 }
Real World Use Cases
1. Default settings plus user settings
const defaults = { theme: 'light', notifications: true };
const userSettings = { theme: 'dark' };
const settings = { ...defaults, ...userSettings };
This keeps default values but lets user choices override them.
2. Building API request options
const baseOptions = { method: 'GET', headers: { Accept: 'application/json' } };
const authOptions = { token: 'abc123' };
const options = { ...baseOptions, ...authOptions };
This is common when preparing request objects.
3. Updating state in frontend apps
const state = { loading: true, data: null };
const nextState = { ...state, loading: false, data: [1, 2, 3] };
This is common in React and other UI libraries where new objects are preferred over mutation.
4. Combining form data
const basicInfo = { name: 'Ava', age: 25 };
const contactInfo = { email: 'ava@example.com' };
const formData = { ...basicInfo, ...contactInfo };
This helps gather related values before saving or sending them.
Real Codebase Usage
In real projects, developers usually merge objects in a few standard ways.
Merging defaults with overrides
const defaultConfig = {
timeout: 5000,
retries: 2
};
function createConfig(customConfig) {
return { ...defaultConfig, ...customConfig };
}
This pattern is everywhere in libraries and application setup.
Using immutable updates
Instead of changing an existing object, many codebases create a new one:
const updatedUser = { ...user, isAdmin: true };
This is safer in state management because it avoids accidental side effects.
Guarding against missing values
Developers often check that inputs are objects before merging:
function mergeFlatObjects(a, b) {
if (!a || typeof a !== 'object') return b;
if (!b || typeof b !== 'object') return a;
return { ...a, ...b };
}
This is a simple guard clause pattern.
Overriding only selected properties
const request = {
...baseRequest,
method: 'POST'
};
This copies all shared values and then changes only what is needed.
Validation before merging
When merging user input, codebases often validate keys or values first to avoid unexpected data entering the system.
Common Mistakes
1. Expecting a custom .merge() method to exist
This will not work on normal JavaScript objects:
const obj1 = { food: 'pizza' };
const obj2 = { animal: 'dog' };
obj1.merge(obj2); // Error
Plain objects do not have a built-in .merge() method.
Use:
Object.assign(obj1, obj2);
or:
const merged = { ...obj1, ...obj2 };
2. Forgetting that Object.assign() can mutate the target
const obj1 = { a: 1 };
const obj2 = { b: 2 };
Object.assign(obj1, obj2);
console.log(obj1); // changed
If you want a new object, use:
const merged = Object.assign({}, obj1, obj2);
3. Not understanding overwrite order
const a = { x: 1 };
const b = { x: 2 };
const merged = { ...a, ...b };
console.log(merged.x); // 2
The later source wins.
4. Assuming this is a deep merge
const a = { settings: { darkMode: false } };
const b = { settings: { fontSize: 18 } };
const merged = { ...a, ...b };
console.log(merged);
// { settings: { fontSize: 18 } }
The nested settings object is replaced, not combined deeply.
5. Mutating objects when immutability is expected
In frameworks and shared code, changing the original object can cause bugs.
Prefer:
const newObject = { ...oldObject, updated: true };
when you want safer updates.
Comparisons
| Approach | Mutates original? | Creates new object? | Common use | Notes |
|---|---|---|---|---|
Object.assign(obj1, obj2) | Yes | No | Directly add properties to an existing object | Good when mutation is acceptable |
Object.assign({}, obj1, obj2) | No | Yes | Merge into a fresh object | Clear and widely supported |
{ ...obj1, ...obj2 } | No | Yes | Modern JavaScript merging | Short and readable |
Object.assign() vs spread syntax
Object.assign()is older and explicit- Spread syntax is newer and often easier to read
- Both perform shallow copies for plain object merging
Mutating vs non-mutating merge
| Style | Example | When to use |
|---|---|---|
| Mutating | Object.assign(target, source) | When you intentionally want to update the existing object |
| Non-mutating | { ...target, ...source } | When you want safer, predictable code |
In modern code, non-mutating merges are usually preferred unless there is a specific reason to update the original object.
Cheat Sheet
// Mutate obj1 by copying obj2 into it
Object.assign(obj1, obj2);
// Create a new merged object
const merged = Object.assign({}, obj1, obj2);
// Modern syntax for a new merged object
const merged = { ...obj1, ...obj2 };
Rules to remember
- Objects are merged by copying top-level properties
- If keys conflict, the later object wins
Object.assign(target, source)changestarget- Spread syntax usually creates a new object
- Both are shallow merges, not deep merges
Conflict example
const a = { x: 1 };
const b = { x: 2 };
const c = { ...a, ...b };
// c.x is 2
Safe default pattern
const options = { ...defaultOptions, ...userOptions };
Important edge case
Nested objects are not deeply merged:
const a = { config: { debug: true } };
const b = { config: { port: 3000 } };
const c = { ...a, ...b };
// c.config is { port: 3000 }
FAQ
Is there a built-in merge method on JavaScript objects?
No. Plain JavaScript objects do not have a .merge() method. Use Object.assign() or object spread syntax instead.
What is the easiest way to merge two objects in JavaScript?
For modern JavaScript, the most common approach is:
const merged = { ...obj1, ...obj2 };
Does Object.assign() change the original object?
Yes, it changes the target object you pass in as the first argument.
Which value wins if both objects have the same key?
The value from the later object wins.
Is object spread the same as deep merge?
No. It only copies top-level properties.
Should I use Object.assign() or spread syntax?
Use spread syntax for readability in modern code. Use Object.assign() if you specifically want to mutate an existing target or need that style for compatibility.
Can I merge more than two objects?
Yes.
const result = { ...a, ...b, ...c };
or:
Object.assign({}, a, b, c);
Mini Project
Description
Build a small settings merger for a JavaScript app. The app has default settings, and a user can provide their own overrides. You will combine both objects into one final configuration object. This demonstrates one of the most common real-world uses of object merging.
Goal
Create a function that merges default settings with user-provided settings and returns the final result without changing the original defaults.
Requirements
- Create a
defaultSettingsobject with at least three properties. - Create a
userSettingsobject that overrides at least one property and adds one new property. - Write a function that returns a new merged object.
- Do not mutate the original
defaultSettingsobject. - Print the merged result and the original defaults to verify the behavior.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.