How to Merge Two Arrays in JavaScript Full Guide
Learn every way to merge arrays in JavaScript. Covers the spread operator, concat, push, unshift, reduce, merging without duplicates, merging arrays of objects, performance comparisons, and common mistakes.
Merging arrays is one of the most common operations in JavaScript. Whether you are combining API responses, concatenating search results, or building a unified dataset from multiple sources, you need a reliable way to join two or more arrays into one. JavaScript provides several approaches, each with different behavior around immutability, performance, and readability.
This guide covers every method for merging arrays, from the modern spread operator to classic techniques, plus patterns for merging without duplicates and merging arrays of objects.
Method 1: Spread Operator (Recommended)
The spread operator is the most readable and widely used approach. It creates a new array without mutating the originals.
const fruits = ["apple", "banana", "cherry"];
const vegetables = ["carrot", "broccoli", "spinach"];
const combined = [...fruits, ...vegetables];
console.log(combined);
// ["apple", "banana", "cherry", "carrot", "broccoli", "spinach"]
console.log(fruits); // ["apple", "banana", "cherry"] -- unchanged
console.log(vegetables); // ["carrot", "broccoli", "spinach"] -- unchangedMerging Multiple Arrays
const team1 = ["Alice", "Bob"];
const team2 = ["Charlie", "Diana"];
const team3 = ["Eve", "Frank"];
const allTeams = [...team1, ...team2, ...team3];
console.log(allTeams);
// ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]Adding Elements While Merging
const existing = [1, 2, 3];
const additional = [7, 8, 9];
const withMiddle = [...existing, 4, 5, 6, ...additional];
console.log(withMiddle);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]Method 2: Array.concat()
The concat() method returns a new array by joining the original with one or more arrays or values. It predates the spread operator and is fully supported in every environment.
const a = [1, 2, 3];
const b = [4, 5, 6];
const merged = a.concat(b);
console.log(merged); // [1, 2, 3, 4, 5, 6]
// Chaining multiple
const c = [7, 8, 9];
const all = a.concat(b, c);
console.log(all); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Concat with individual values
const withValues = a.concat(4, 5, [6, 7]);
console.log(withValues); // [1, 2, 3, 4, 5, 6, 7]Method 3: Array.push() with Spread (Mutating)
If you want to add elements to an existing array instead of creating a new one, use push with the spread operator:
const primary = ["HTML", "CSS", "JavaScript"];
const secondary = ["React", "Node.js", "TypeScript"];
primary.push(...secondary);
console.log(primary);
// ["HTML", "CSS", "JavaScript", "React", "Node.js", "TypeScript"]
// Note: primary is mutatedpush() vs. Spread into New Array
// Immutable: creates a new array
const immutable = [...primary, ...secondary];
// Mutable: modifies 'primary' in place
primary.push(...secondary);Method 4: Array.unshift() with Spread
To prepend one array before another, use unshift with spread:
const tasks = ["code", "test", "deploy"];
const priorityTasks = ["plan", "design"];
tasks.unshift(...priorityTasks);
console.log(tasks);
// ["plan", "design", "code", "test", "deploy"]Method 5: reduce() for Complex Merging
Use reduce when you need to merge with transformation or filtering logic:
const arrays = [[1, 2], [3, 4], [5, 6], [7, 8]];
const flat = arrays.reduce((result, current) => [...result, ...current], []);
console.log(flat); // [1, 2, 3, 4, 5, 6, 7, 8]
// With filtering during merge
const numbers = [[1, -2, 3], [-4, 5, -6], [7, 8, -9]];
const positiveOnly = numbers.reduce((result, current) => {
return [...result, ...current.filter((n) => n > 0)];
}, []);
console.log(positiveOnly); // [1, 3, 5, 7, 8]Merging Without Duplicates
Using Set
The simplest way to merge arrays and remove duplicates is combining spread with Set:
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [3, 4, 5, 6, 7];
const unique = [...new Set([...arr1, ...arr2])];
console.log(unique); // [1, 2, 3, 4, 5, 6, 7]Using filter() for Deduplication
const arr1 = ["JavaScript", "Python", "Go"];
const arr2 = ["Python", "Rust", "Go", "Java"];
const merged = [...arr1, ...arr2.filter((item) => !arr1.includes(item))];
console.log(merged); // ["JavaScript", "Python", "Go", "Rust", "Java"]Deduplicating Arrays of Objects by Key
const list1 = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
const list2 = [
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
];
const mergedUnique = [...list1, ...list2].reduce((acc, item) => {
if (!acc.some((existing) => existing.id === item.id)) {
acc.push(item);
}
return acc;
}, []);
console.log(mergedUnique);
// [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }, { id: 3, name: "Charlie" }]Merging Arrays of Objects
Combining API Response Pages
const page1 = [
{ id: 1, title: "Introduction to JS", views: 1200 },
{ id: 2, title: "Variables Guide", views: 950 }
];
const page2 = [
{ id: 3, title: "Functions Tutorial", views: 1800 },
{ id: 4, title: "Arrays Explained", views: 2100 }
];
const allArticles = [...page1, ...page2];
console.log(allArticles.length); // 4
// Sort merged results by views
const sorted = allArticles.sort((a, b) => b.views - a.views);
console.log(sorted[0].title); // "Arrays Explained"Merge and Group by Category
const electronics = [
{ name: "Laptop", price: 999, category: "electronics" },
{ name: "Phone", price: 699, category: "electronics" }
];
const clothing = [
{ name: "Shirt", price: 29, category: "clothing" },
{ name: "Jacket", price: 89, category: "clothing" }
];
const inventory = [...electronics, ...clothing];
// Group by category using reduce
const grouped = inventory.reduce((groups, item) => {
const key = item.category;
groups[key] = groups[key] || [];
groups[key].push(item);
return groups;
}, {});
console.log(Object.keys(grouped)); // ["electronics", "clothing"]Comparison Table
| Method | Mutates Original | Creates New Array | Performance (Large Arrays) | Readability |
|---|---|---|---|---|
[...a, ...b] | No | Yes | Good | Excellent |
a.concat(b) | No | Yes | Good | Good |
a.push(...b) | Yes | No | Best (no copy) | Good |
a.unshift(...b) | Yes | No | Slower (shifts indices) | Fair |
reduce merge | No | Yes | Depends on logic | Complex |
Common Mistakes
Accidentally Nesting Instead of Merging
const a = [1, 2, 3];
const b = [4, 5, 6];
// Bug: creates a nested array
const nested = [a, b];
console.log(nested); // [[1, 2, 3], [4, 5, 6]]
// Fix: spread both arrays
const flat = [...a, ...b];
console.log(flat); // [1, 2, 3, 4, 5, 6]push() Without Spread
const items = [1, 2, 3];
const moreItems = [4, 5, 6];
// Bug: pushes the array itself as a single element
items.push(moreItems);
console.log(items); // [1, 2, 3, [4, 5, 6]]
// Fix: spread into push
const items2 = [1, 2, 3];
items2.push(...moreItems);
console.log(items2); // [1, 2, 3, 4, 5, 6]Shallow Copy with Object Arrays
const original = [{ name: "Alice" }, { name: "Bob" }];
const copy = [...original];
copy[0].name = "Charlie";
console.log(original[0].name); // "Charlie" -- original mutated!
// Fix: deep copy when objects must be independent
const safeCopy = structuredClone(original);Best Practices
- Use spread for immutable merges.
[...a, ...b]is the default choice for combining arrays without side effects. - Use push with spread for performance. When mutation is acceptable and you are adding to an existing array,
arr.push(...newItems)avoids creating a copy. - Deduplicate with Set.
[...new Set([...a, ...b])]is the most concise approach for primitive values. - Use reduce for complex merges. When you need filtering, transformation, or grouping during the merge, reduce provides full control.
- Be aware of shallow copies. Spreading arrays of objects shares nested references. Use
structuredClone()when full independence is required.
Rune AI
Key Insights
- Spread operator is the modern default:
[...a, ...b]creates a new merged array without mutating originals. - concat() is the classic alternative: it behaves identically to spread for merging but uses method chaining syntax.
- push with spread mutates efficiently:
arr.push(...items)is fastest when immutability is not required. - Set deduplication is one line:
[...new Set([...a, ...b])]removes duplicate primitives automatically. - Nested objects require deep awareness: spread produces shallow copies, so merged arrays of objects share inner references.
Frequently Asked Questions
What is the fastest way to merge two arrays in JavaScript?
How do I merge arrays without duplicates?
Does concat mutate the original array?
Can I merge more than two arrays at once?
How do I merge arrays of objects and keep the latest version?
Conclusion
JavaScript offers multiple ways to merge arrays, and the right choice depends on whether you need immutability, deduplication, or raw performance. The spread operator is the default for most situations because it is immutable, readable, and works with any number of arrays. Use push with spread when mutation is acceptable and performance matters, Set for automatic deduplication of primitives, and reduce for complex merge-with-transform logic. Understanding these options lets you handle any array combination scenario cleanly.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.