jsguides

Array.prototype.concat()

concat(...items)

The concat() method merges (concatenates) two or more arrays into a new array. It does not modify the original arrays - instead, it returns a brand new array containing all the elements.

Syntax

array.concat(...items)
  • items: Arrays or values to merge into the new array. Can be arrays or primitive values.
  • Returns: A new array containing all elements from the original array and all items passed as arguments.

The method accepts any number of arguments and flattens array arguments one level deep. The TypeScript signature below formalizes this contract: what types concat() accepts and what it guarantees to return.

TypeScript Signature

interface Array<T> {
  concat(...items: (T | ConcatArray<T>)[]): T[];
}

interface ConcatArray<T> {
  length: number;
  [n: number]: T;
}

The TypeScript definition confirms the shape. The parameters table below breaks each field into readable detail: the type signature for items, the lack of a default value, and the automatic flattening behavior for strings and numbers.

Parameters

ParameterTypeDefaultDescription
items(T | ConcatArray<T>)[]-Arrays or values to concatenate. Strings and numbers are flattened automatically.

Examples

Basic concatenation

const fruits = ["apple", "banana"];
const vegetables = ["carrot", "lettuce"];

const produce = fruits.concat(vegetables);
console.log(produce);
// ["apple", "banana", "carrot", "lettuce"]

// Original arrays remain unchanged
console.log(fruits);
// ["apple", "banana"]
console.log(vegetables);
// ["carrot", "lettuce"]

Two simple arrays produce a flat merged copy, and the originals stay intact: fruits and vegetables remain unchanged. The next example passes three arrays to concat(), showing that the method accepts any number of arguments and merges them in the order they appear.

Concatenating multiple arrays

const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = [5, 6];

const combined = arr1.concat(arr2, arr3);
console.log(combined);
// [1, 2, 3, 4, 5, 6]

// You can also use spread operator as alternative
const spreadCombined = [...arr1, ...arr2, ...arr3];
console.log(spreadCombined);
// [1, 2, 3, 4, 5, 6]

The call above merges three arrays and also shows the spread operator as an alternative with the same result. The next example mixes arrays with primitive values, demonstrating that concat() accepts both forms in a single call and flattens the arrays while appending primitives as-is.

Concatenating values and arrays

const numbers = [1, 2];

// Mix arrays and primitive values
const mixed = numbers.concat([3, 4], 5, [6, 7]);
console.log(mixed);
// [1, 2, 3, 4, 5, 6, 7]

// Strings are flattened automatically
const letters = ["a", "b"].concat("c", ["d", "e"]);
console.log(letters);
// ["a", "b", "c", "d", "e"]

The mixed call above shows concat() flattening one level — the array arguments are unpacked, but the number 5 is appended directly. The next example confirms the flattening limit: nested arrays pass through with their structure intact, which is often the desired behavior when you are working with grouped data. For deeper flattening, flat() is the explicit next step.

Deep flattening with concat

// concat only flattens one level
const nested = [1, 2].concat([[3, 4], [5, 6]]);
console.log(nested);
// [1, 2, [3, 4], [5, 6]]

// For deep flattening, use flat()
const deepNested = [[1, 2], [[3, 4]]];
console.log(deepNested.flat(2));
// [1, 2, 3, 4]

The nested example confirms that concat() stops at one level of flattening, while flat(2) reaches deeper. The next pattern uses concat() with no arguments — a concise way to produce a shallow copy of an array, which is useful when you need a new reference without touching the original.

Common Patterns

Copying an Array

const original = [1, 2, 3];
const copy = original.concat();

console.log(copy);
// [1, 2, 3]
console.log(copy === original);
// false

An empty call creates a shallow copy with a new reference — copy === original is false. The next patterns use the same non-mutating behavior to place elements at specific positions: before the original content by passing arrays to concat() on the left, or after it by calling concat() on the original with the new elements as arguments.

Prepending and appending elements

const nums = [3, 4, 5];

// Add elements at the start
const withStart = [1, 2].concat(nums);
console.log(withStart);
// [1, 2, 3, 4, 5]

// Add elements at the end
const withEnd = nums.concat([6, 7]);
console.log(withEnd);
// [3, 4, 5, 6, 7]

Why concat() still matters

concat() is still a strong choice when you want to combine arrays without mutating the inputs. That property is useful in reducers, data pipelines, and any code that treats arrays as values rather than containers to be edited in place. It also makes the result easier to reason about because the original arrays remain available for later use.

The method only flattens one level of array-like input, which is often exactly what you want. If you are merging nested collections, that shallow behavior keeps structure intact. If you need a fully flattened result, flat() is a clearer follow-up step because it says exactly how much nesting you want to remove.

concat() vs Spread

The spread operator, [...a, ...b], can express the same idea in many cases. Use concat() when you want a method call that reads like an operation on an existing array, especially if the code already uses other array methods. Use spread when you are building a brand new literal and want to keep the structure visually compact.

There are also small semantic differences around array-like values and shallow flattening. concat() has a long history and keeps its own rules about what gets flattened. Spread is often nicer for simple merges, but concat() remains a useful option when you want those built-in rules and a method-style API.

Common edge cases

concat() does not mutate any source array, but it does allocate a new result. That means repeated concatenation in a loop can create extra work. In hot paths, collect items into one array and concatenate once rather than building the final list piece by piece.

Sparse arrays keep their holes, so be careful if you expect every slot to contain a value. Primitive values are appended as-is, while arrays are flattened one level. That behavior makes the method predictable, but it also means you should think through whether you want values, lists, or a mix of both before calling it.

Performance Notes

  • concat() creates a new array, which has memory overhead
  • For large arrays or frequent concatenations, consider using spread operator [...arr1, ...arr2] which has similar performance
  • If building an array incrementally in a loop, consider using push() with spread or Array.from() for better performance

When to Use

  • When you need a new merged array without modifying originals (immutable pattern)
  • When concatenating multiple arrays in a single operation
  • When you need to add primitive values alongside arrays

See Also