Array.prototype.unshift()
unshift(...items) unshift() adds one or more elements to the beginning of an array and returns the new length. It modifies the array in place, shifting existing elements to higher indices.
Syntax
arr.unshift(element1)
arr.unshift(element1, element2)
arr.unshift(element1, element2, /* ... */ elementN)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
items | any | — | Elements to add to the beginning of the array |
Like push(), the items parameter is variadic — pass zero or more values of any type. Each argument is prepended in the order it appears, so unshift(1, 2, 3) places 1 at index 0, then 2 at index 0 (shifting 1 to index 1), then 3 at index 0. The final order is [3, 2, 1, ...existing].
Examples
Basic usage
const colors = ["blue", "green"];
colors.unshift("red");
console.log(colors);
// ["red", "blue", "green"]
The single-argument form is the most common use of unshift(). The method shifts every existing element one position to the right and places the new element at index 0. As with push(), the return value is the new length, not the inserted element — if you need the prepended value, you already have it in the variable you passed in.
Adding multiple elements
const nums = [3, 4, 5];
const newLength = nums.unshift(1, 2);
console.log(nums); // [1, 2, 3, 4, 5]
console.log(newLength); // 5
When multiple arguments are passed, each one is inserted at the front in sequence. This means the first argument ends up at the highest index among the newly inserted items, and the last argument lands at index 0. The elements shift right as a group by the total number of arguments, not one at a time, so the relative order of the existing elements is preserved.
Using unshift with zero arguments
const arr = [1, 2, 3];
const length = arr.unshift();
console.log(length); // 3 (no change)
Just like push(), calling unshift() with no arguments is a no-op that returns the current length. The three examples above cover the full calling convention: a single element, a batch of elements inserted in order, and the zero-argument edge case.
Common Patterns
Prepending elements
const users = ["charlie", "diana"];
users.unshift("alice", "bob");
console.log(users);
// ["alice", "bob", "charlie", "diana"]
Prepending multiple names or items at once keeps the batch in order — "alice" lands before "bob" in the result. This is often cleaner than calling unshift() in a loop, which would reverse the order of the batch unless you iterate in reverse. The single-call approach also triggers only one reindex operation, which matters for larger arrays.
Implementing a priority queue
class PriorityQueue {
constructor() {
this.items = [];
}
enqueue(item, priority) {
// Simple implementation: higher priority = earlier position
const entry = { item, priority };
let added = false;
for (let i = 0; i < this.items.length; i++) {
if (priority > this.items[i].priority) {
this.items.splice(i, 0, entry);
added = true;
break;
}
}
if (!added) {
this.items.push(entry);
}
}
dequeue() {
return this.items.shift().item;
}
}
const pq = new PriorityQueue();
pq.enqueue("low priority", 1);
pq.enqueue("high priority", 10);
pq.enqueue("medium priority", 5);
console.log(pq.dequeue()); // "high priority"
console.log(pq.dequeue()); // "medium priority"
console.log(pq.dequeue()); // "low priority"
This priority queue uses splice() for insertion because the correct position depends on priority comparison, not just prepending everything. The unshift() method is not directly used here, but the example illustrates why prepend semantics matter — when the front of the array carries meaning, you need to place items at specific positions rather than always at the end.
Behavior Notes
unshift()accepts zero arguments, which returns the current length without changes- This method modifies the original array (mutating method)
- All existing elements shift up by the number of elements added
Performance considerations
unshift() is O(n) because it must shift every existing element to a higher index to make room at the beginning. For large arrays where you frequently prepend elements, consider using a different data structure such as a linked list, or reversing your logic to append and reverse at read time.
// Slow for large arrays — O(n) per call
const history = [];
history.unshift(newEvent); // shifts everything
// Faster pattern: append and reverse when needed
const log = [];
log.push(newEvent); // O(1)
const chronological = log.toReversed(); // only when needed
When unshift() makes sense
unshift() is useful when the front of the array is semantically important, such as a priority queue, a history list, or a stack where the newest item should appear first. The method communicates that the left side of the array is the insertion point, which can make the code easier to follow than manually shifting indexes around. It is a good example of a method that is simple to read but should still be used with care on large arrays.
Preserving element order
When unshift is called with multiple arguments, they are inserted in the order provided — not reversed:
const arr = [4, 5];
arr.unshift(1, 2, 3);
console.log(arr); // [1, 2, 3, 4, 5]
The argument order matches insertion order — 1 goes in first, then 2 in front of it, then 3 in front of 2. The key point is that a single unshift(a, b, c) call is not equivalent to three separate calls unshift(a); unshift(b); unshift(c). The single call preserves the argument order as-is; the three separate calls reverse it because each subsequent call pushes the previous value one slot right.
This is different from calling unshift three times with individual values, which would reverse the order:
const arr2 = [4, 5];
arr2.unshift(3);
arr2.unshift(2);
arr2.unshift(1);
console.log(arr2); // [1, 2, 3, 4, 5] — same result in this case, but only because we added in reverse
Both approaches produce the same final array here, but the single-call version is clearer and avoids the mental gymnastics of reversing the argument order. When you see arr.unshift(1, 2, 3), the result [1, 2, 3, ...] matches the visual order of the arguments, which makes the code easier to scan and reason about at a glance.
Immutable alternative
For non-mutating prepend, use the spread operator to create a new array:
const original = [3, 4, 5];
const withPrefix = [1, 2, ...original];
console.log(original); // [3, 4, 5] — unchanged
console.log(withPrefix); // [1, 2, 3, 4, 5]
The spread operator is the idiomatic immutable alternative to unshift() in modern JavaScript. It creates a new array, leaving the original untouched, which is essential in React state updates and functional programming patterns. The spread approach is also O(n) since it copies all elements, but the copy is explicit and the original remains safe for any other code holding a reference to it.
Return value
unshift() returns the new length of the array after the elements are added. This return value is often ignored, but it is useful when you need to act on the updated length immediately — for example, to check whether the array has exceeded a threshold after prepending.
const queue = ['b', 'c'];
const newLen = queue.unshift('a');
console.log(newLen); // 3
Unlike push(), which is symmetric and also returns the new length, unshift() shifts all existing elements — so its performance cost scales with array size. For a fixed-size buffer where you frequently add and remove from both ends, a deque implementation is more efficient.
See Also
- Array.prototype.shift() — Remove the first element
- Array.prototype.push() — Add to the end
- Array.prototype.splice() — Add/remove elements at any position