How to merge two arrays in JavaScript
Merging arrays is essential when combining data from multiple sources, concatenating user selections, or building unified datasets in JavaScript applications. With over 25 years of experience in software development and as the creator of CoreUI, I’ve implemented array merging extensively in components like multi-select filters, data aggregation systems, and navigation builders where multiple arrays need to be combined. The most modern and efficient solution is using the ES6 spread operator, which creates a new array without mutating the original arrays. This approach is clean, readable, and performs well for most use cases.
Use the spread operator to merge two arrays into a new array.
const fruits = ['apple', 'banana']
const vegetables = ['carrot', 'broccoli']
const combined = [...fruits, ...vegetables]
// Result: ['apple', 'banana', 'carrot', 'broccoli']
The spread operator ... expands each array’s elements into the new array literal. In this example, ...fruits expands to 'apple', 'banana' and ...vegetables expands to 'carrot', 'broccoli', creating a new array with all elements in order. This method doesn’t modify the original arrays and preserves the element ordering from each source.
1. Inserting Elements During a Merge
One advantage of the spread operator over concat() is that you can insert additional elements between the merged arrays directly in the array literal.
const header = ['Dashboard', 'Analytics']
const footer = ['Settings', 'Logout']
// Insert a divider between the two groups
const navItems = [...header, 'Divider', ...footer]
// Result: ['Dashboard', 'Analytics', 'Divider', 'Settings', 'Logout']
// Prepend and append elements
const fullNav = ['Home', ...header, ...footer, 'Help']
// Result: ['Home', 'Dashboard', 'Analytics', 'Settings', 'Logout', 'Help']
This pattern is common when building navigation structures in CoreUI Nav components where you need to combine different menu groups with separators or fixed items between them.
2. Merging More Than Two Arrays
The spread operator scales naturally to any number of arrays. Simply spread each one into the target array literal.
const admins = ['Alice', 'Bob']
const editors = ['Charlie', 'Diana']
const viewers = ['Eve', 'Frank', 'Grace']
const allUsers = [...admins, ...editors, ...viewers]
// Result: ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace']
console.log(allUsers.length)
// Result: 7
This approach is useful in role-based systems where you need to aggregate users from different permission groups into a single list. In CoreUI Smart Table, you might combine data from multiple API endpoints before displaying them in a unified table view.
3. Merging with concat()
The concat() method is the classic alternative to the spread operator. It creates a new array by appending one or more arrays to the original.
const primary = ['red', 'blue', 'yellow']
const secondary = ['green', 'orange', 'purple']
// Using concat
const allColors = primary.concat(secondary)
// Result: ['red', 'blue', 'yellow', 'green', 'orange', 'purple']
// Chaining multiple concat calls
const tertiary = ['pink', 'teal']
const palette = primary.concat(secondary, tertiary)
// Result: ['red', 'blue', 'yellow', 'green', 'orange', 'purple', 'pink', 'teal']
For very large arrays (tens of thousands of elements), concat() can be faster than the spread operator because it avoids the overhead of expanding elements into function arguments. Both methods produce a new array without modifying the originals.
4. Merging Arrays of Objects
When working with arrays of objects — such as rows in a data table or items in a list — the spread operator works the same way. However, the merged array contains references to the original objects, not deep copies.
const localUsers = [
{ id: 1, name: 'Alice', source: 'local' },
{ id: 2, name: 'Bob', source: 'local' }
]
const remoteUsers = [
{ id: 3, name: 'Charlie', source: 'api' },
{ id: 4, name: 'Diana', source: 'api' }
]
const allUsers = [...localUsers, ...remoteUsers]
// Result: array with 4 user objects
// Objects are shared references, not copies
allUsers[0].name = 'Alicia'
console.log(localUsers[0].name)
// Result: 'Alicia' — original is also affected
If you need independent copies, use structuredClone() before merging: [...structuredClone(localUsers), ...structuredClone(remoteUsers)]. This is important when merging data sources in CoreUI List Group components where you might modify the merged list without affecting the originals. For more on copying, see how to clone an array.
5. Removing Duplicates After Merging
Merging arrays often produces duplicates. Use Set to filter them out for primitive values, or Map for arrays of objects.
// Primitives: use Set
const tags1 = ['react', 'javascript', 'css']
const tags2 = ['javascript', 'typescript', 'css']
const uniqueTags = [...new Set([...tags1, ...tags2])]
// Result: ['react', 'javascript', 'css', 'typescript']
// Objects: use Map with a unique key
const list1 = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
const list2 = [{ id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
const merged = [...list1, ...list2]
const unique = [...new Map(merged.map(item => [item.id, item])).values()]
// Result: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
The Set approach works instantly for strings and numbers. For objects, the Map strategy uses a unique key (like id) to keep only the last occurrence of each entry. For more details, see how to remove duplicates from an array.
6. Conditional Merging
Sometimes you only want to include an array’s contents based on a condition. The spread operator combined with a ternary or empty array makes this clean.
const baseItems = ['Home', 'About']
const isAdmin = true
const adminItems = ['Users', 'Settings']
const isPremium = false
const premiumItems = ['Analytics', 'Reports']
const menu = [
...baseItems,
...(isAdmin ? adminItems : []),
...(isPremium ? premiumItems : [])
]
// Result: ['Home', 'About', 'Users', 'Settings']
Spreading an empty array [] adds nothing, making this a safe and concise pattern for building dynamic navigation. This is the exact approach used in CoreUI Sidebar configurations where menu items vary based on user roles or feature flags.
7. Merging and Sorting
After merging, you frequently need to sort the resulting array. Chain the spread merge with .sort() for a clean one-liner.
const prices1 = [29.99, 9.99, 49.99]
const prices2 = [19.99, 39.99, 14.99]
// Merge and sort ascending
const allPrices = [...prices1, ...prices2].sort((a, b) => a - b)
// Result: [9.99, 14.99, 19.99, 29.99, 39.99, 49.99]
// Merge objects and sort by property
const events1 = [{ date: '2026-01-15', title: 'Launch' }]
const events2 = [{ date: '2026-01-10', title: 'Preview' }]
const timeline = [...events1, ...events2].sort(
(a, b) => new Date(a.date) - new Date(b.date)
)
// Result: [{ date: '2026-01-10', title: 'Preview' }, { date: '2026-01-15', title: 'Launch' }]
Remember that .sort() mutates the array in place. Since the spread operator already creates a new array, this is safe — the originals remain untouched.
Best Practice Note:
This is the same approach we use in CoreUI components for combining configuration arrays and merging user preferences.
Use the spread operator for most merges — it’s readable and handles insertion, conditionals, and chaining naturally. Switch to concat() for very large arrays where performance matters. For related operations, see how to clone an array, how to add items to an array, and how to flatten nested arrays.



