Array.prototype.unshift()

push at the other end, with the same surprising return value and shift's performance cost. Prepending in a loop is quadratic.

Array methodES3 (1999)Live demo
Common call
items.unshift(value)
Returns
number — the new length
Replaces
items.splice(0, 0, value)
Watch out
O(n) per call, and multiple arguments keep their order
array.unshift(...items...items — Any number of values, inserted at the front IN THE ORDER GIVEN — unshift(1, 2) puts 1 first, not 2.type: any · default: none)
→ number

Demo

Live evaluation
Try:
Inputs
itemsnumber[]starting array, comma separated
valuenumbervalue to prepend
Output
[2, 3, 4].unshift(1)
4

The outputs are NUMBERS — the new length, exactly as with push. Prepending to a three-element array gives 4, not the array. The element goes to the front and every existing element moves up one index, which is why this costs O(n) where push costs O(1).

Parameters

NameTypeRequiredDescription
...itemsanyno (none)Any number of values, inserted at the front IN THE ORDER GIVEN — unshift(1, 2) puts 1 first, not 2.

Return value

number — The NEW length of the array — like push, not the array itself. The array is modified in place.

Common patterns

Prepend a single item
Fine for small arrays.
items.unshift(newest);
Non-mutating prepend
Usually preferable, and it returns the array.
const next = [value, ...items];
Build reversed, then reverse
Avoids the quadratic cost of repeated prepending.
for (const x of input) out.push(x);
out.reverse();

Examples

1. Returns the length
const a = [2, 3]; a.unshift(1)
Returns
3
2. The array after
const a = [2, 3]; a.unshift(1); a
Returns
[1, 2, 3]
3. Order is preserved
const a = [3]; a.unshift(1, 2); a
Returns
[1, 2, 3]
4. Onto empty
const a = []; a.unshift(1); a
Returns
[1]
5. Non-mutating
const next = [1, ...[2, 3]]; next
Returns
[1, 2, 3]
6. Arrays nest
const a = [2]; a.unshift([1]); a
Returns
[[1], 2]

Pitfalls

1. It returns the new length, not the array
Identical to push. Assigning the result leaves you with an integer, and the failure only appears when something later tries to treat it as an array.
Got a number
const next = items.unshift(value);
4
Spread instead
const next = [value, ...items];
the array
2. Prepending in a loop is quadratic
Every call re-indexes the whole array, so building an array front-to-back this way is O(n²). Push and reverse once instead, which is linear.
Quadratic
for (const x of input) out.unshift(x);
O(n²)
Push then reverse
for (const x of input) out.push(x);
out.reverse();
O(n)
3. Unshifting in a loop reverses your data
One call with several arguments keeps their order, but calling unshift once per element does not — each new element lands in front of the previous one. Switching between the two forms silently flips the result.
Loop reverses
const a = [3];
for (const x of [1, 2]) a.unshift(x);
a
[2, 1, 3]
One call keeps order
const a = [3];
a.unshift(1, 2);
a
[1, 2, 3]

When to use

Use it
  • Prepending once to a small array you own
  • Inserting at the front where a spread would be wasteful
Reach for something else
  • Prepending repeatedly → push then reverse
  • The array is shared or state → [value, ...items]
  • You want the array back → a spread returns it; unshift returns a number

Notes

Complexity
O(n) — every existing element moves up one index
Return
A number — the new length; the array is modified in place
CPython impl
V8: Builtins-array-unshift.tq
Memory
May reallocate; the whole backing store is re-indexed
Thread-safe
Single-threaded; mutating a shared array is the hazard here

FAQ

Because it changes every index. Adding to the end leaves existing positions valid; adding to the front pushes element 0 to 1, 1 to 2, and so on through the whole array. push is O(1) amortised, unshift is O(n).

History

ES3
unshift standardised in 1999 alongside push, pop and shift.
ES2015
Spread syntax made [value, ...items] the idiomatic non-mutating prepend.