How Array Concatenation Simplifies Data Merging
Mastering array concatenation with the spread operator transforms how you handle multiple data sources. Whether combining API responses, merging paginated results, or joining search data, this technique provides clean, readable syntax that eliminates common pitfalls with traditional concat() methods.
TL;DR
- Use spread syntax
[...arr1, ...arr2]
for clean array joining- Outperforms concat() with multiple arrays and better readability
- Essential for combining API responses and paginated data
- Works seamlessly with dynamic array counts and conditional merging
const merged = [...arr1, ...arr2, ...arr3]
The Array Concatenation Challenge
You're building a dashboard that displays data from multiple API endpoints. The traditional approach uses concat() methods that become unwieldy with multiple data sources, making the code harder to read and prone to mutation bugs.
// The problematic approach with concat()
const searchResults = ['result1', 'result2']
const apiData = ['data1', 'data2', 'data3']
const cachedItems = ['cache1']
function combineDataOldWay(search, api, cache) {
let combined = search.concat(api)
combined = combined.concat(cache)
console.log('Traditional concat result:', combined)
return combined
}
console.log('Final array:', combineDataOldWay(searchResults, apiData, cachedItems))
Modern array concatenation with spread syntax eliminates mutation concerns and provides crystal-clear intent:
// The elegant spread solution
const searchResults = ['result1', 'result2']
const apiData = ['data1', 'data2', 'data3']
const cachedItems = ['cache1']
function combineDataNewWay(search, api, cache) {
const combined = [...search, ...api, ...cache]
console.log('Modern spread result:', combined)
console.log('Original arrays unchanged:', search.length, api.length, cache.length)
return combined
}
console.log('Final array:', combineDataNewWay(searchResults, apiData, cachedItems))
Best Practises
Use array concatenation when:
- ✅ Combining multiple API responses into a single dataset
- ✅ Merging paginated results from different data sources
- ✅ Building search results that aggregate from multiple endpoints
- ✅ Creating composite arrays without mutating original data
Avoid when:
- 🚩 Working with extremely large arrays (>100k items) where performance matters
- 🚩 Need to maintain references to original arrays after modification
- 🚩 Building for environments that don't support ES6 spread syntax
- 🚩 Simple two-array joins where concat() is more familiar to the team
System Design Trade-offs
Aspect | Spread Syntax | Array.concat() | Array.push() |
---|---|---|---|
Readability | Excellent - visual clarity | Good - familiar method | Poor - imperative style |
Immutability | Immutable by design | Creates new array | Mutates original |
Multiple Arrays | Elegant [...a, ...b, ...c] | Chained .concat() calls | Complex loops required |
Performance | Fast for most use cases | Slightly faster | Fastest but destructive |
Type Safety | Works with any iterable | Array-specific method | Array-specific method |
Browser Support | ES2015+ required | Universal support | Universal support |
More Code Examples
❌ Concat chain nightmare
// Traditional approach with chained concat() calls
function aggregateSearchResults(query) {
// Simulating multiple API endpoint responses
const googleResults = [
{ title: 'Google Result 1', source: 'google', score: 0.95 },
{ title: 'Google Result 2', source: 'google', score: 0.87 },
]
const bingResults = [
{ title: 'Bing Result 1', source: 'bing', score: 0.92 },
{ title: 'Bing Result 2', source: 'bing', score: 0.84 },
{ title: 'Bing Result 3', source: 'bing', score: 0.79 },
]
const localResults = [{ title: 'Local Result 1', source: 'local', score: 0.98 }]
// The painful way with multiple concat operations
let allResults = []
allResults = allResults.concat(googleResults)
allResults = allResults.concat(bingResults)
allResults = allResults.concat(localResults)
// Additional processing requires more chaining
const premiumResults = [{ title: 'Premium Result', source: 'premium', score: 1.0 }]
allResults = allResults.concat(premiumResults)
console.log('Traditional concat approach:')
console.log('Total results:', allResults.length)
allResults.forEach((result, index) =>
console.log(` ${index + 1}. ${result.title} (${result.source})`)
)
return allResults.sort((a, b) => b.score - a.score)
}
const traditionalResults = aggregateSearchResults('javascript tips')
console.log('\nTop result:', traditionalResults[0].title)
✅ Spread syntax wins
// Modern approach with elegant spread syntax
function aggregateSearchResultsModern(query) {
// Simulating multiple API endpoint responses
const googleResults = [
{ title: 'Google Result 1', source: 'google', score: 0.95 },
{ title: 'Google Result 2', source: 'google', score: 0.87 },
]
const bingResults = [
{ title: 'Bing Result 1', source: 'bing', score: 0.92 },
{ title: 'Bing Result 2', source: 'bing', score: 0.84 },
{ title: 'Bing Result 3', source: 'bing', score: 0.79 },
]
const localResults = [{ title: 'Local Result 1', source: 'local', score: 0.98 }]
const premiumResults = [{ title: 'Premium Result', source: 'premium', score: 1.0 }]
// The elegant way with spread syntax
const allResults = [...googleResults, ...bingResults, ...localResults, ...premiumResults]
console.log('Modern spread approach:')
console.log('Total results:', allResults.length)
allResults.forEach((result, index) =>
console.log(` ${index + 1}. ${result.title} (${result.source})`)
)
// Easy to add conditional sources
const hasCache = true
const cacheResults = hasCache ? [{ title: 'Cached Result', source: 'cache', score: 0.88 }] : []
const finalResults = [...allResults, ...cacheResults]
console.log('\nWith cache:', finalResults.length, 'total results')
return finalResults.sort((a, b) => b.score - a.score)
}
const modernResults = aggregateSearchResultsModern('javascript tips')
console.log('\nTop result:', modernResults[0].title)
console.log('Sources used:', [...new Set(modernResults.map((r) => r.source))])
Technical Trivia
The Reddit Pagination Incident of 2019: Reddit's mobile app experienced a critical bug where user feeds showed duplicate posts after implementing array concatenation for infinite scroll. The issue occurred because developers used push() instead of spread syntax, mutating the original array and causing pagination markers to break.
Why concatenation mattered: The bug manifested when users scrolled quickly - the app would merge new posts with existing ones using push(), which modified the original array. This broke pagination tokens and caused the same posts to appear multiple times, leading to user confusion and engagement drops.
Spread syntax prevents mutations: Using `[...existingPosts, ...newPosts]`
creates a new array without touching the originals. This immutable approach ensures pagination state remains consistent, preventing the data corruption that plagued the old implementation and maintaining user experience quality.
Master Array Concatenation: When to Spread
Use spread syntax for array concatenation when combining data from multiple sources, especially API responses and search results. The immutable nature prevents subtle bugs while the readable syntax makes intent crystal clear. Reserve concat() for legacy compatibility or when working with very large arrays where the performance difference matters more than code clarity.