Call stack in JavaScript: how the engine tracks what it is doing

The call stack records the functions currently running so the engine knows where to return. It is what you read inside an error trace.
4 min read
Believemy logo

JavaScript runs one thing at a time. When a function calls another, it has to remember where it came from so it can go back once the work is done.

That return notebook has a name: the call stack. Knowing it changes the way you read an error message, and explains why an unbounded recursion brings the whole program down.


Definition

The call stack is the structure in which the engine stacks the functions currently running. Every call pushes an entry on top, every return pops it off. The last one in is always the first one out.

JAVASCRIPT
function third() {
  throw new Error("something broke");
}
function second() { third(); }
function first() { second(); }

try {
  first();
} catch (error) {
  console.log(error.stack.split("\n").slice(0, 4).join("\n"));
}

// Error: something broke
//     at third
//     at second
//     at first

The trace reads top to bottom like a path in reverse: the first line is the exact spot of the incident, the following ones say who asked for what to get there.

Call stack: push, pop, overflowOn top, three nested calls: first() calls second() which calls third(). The last frame in is the first one out. Below, the same function called with no stopping condition fills the stack up to the engine limit, around ten thousand calls; the next call is never pushed and the program stops on a RangeError.Three nested callsthird()3rd in, 1st outsecond()2nd in, 2nd outfirst()1st in, 3rd outa call pushes, a return popsWith no stopping conditiongoDeeper()RangeErrornever pushedengine limit≈ 10,000 callsgoDeeper()no return,nothing pops


What the stack does not hold

This is the part that surprises people most. A setTimeout() or a Promise does not sit on the stack while it waits: its callback is set aside and only comes back once the stack has been fully emptied.

JAVASCRIPT
console.log("1 start");
setTimeout(() => console.log("3 timer"), 0);
console.log("2 end");

// 1 start
// 2 end
// 3 timer

Even with a zero delay, the timer comes last. That is the job of the Event loop, which only refills the stack once it is empty. Direct consequence: a function that blocks the stack freezes everything else, rendering included.


Stack overflow

The stack has a size limit. Going past it produces an immediate error, almost always caused by a Recursion with no stopping condition.

JAVASCRIPT
let depth = 0;

function goDeeper() {
  depth += 1;
  goDeeper();
}

try {
  goDeeper();
} catch (error) {
  console.log(error.constructor.name); // RangeError
  console.log(depth > 1000);           // true
}
Good to know

An overflow does not always mean infinite recursion. A very deep tree, or two functions calling each other, produce the same error with perfectly correct logic.


Frequently asked questions

Question

What is the maximum stack size?

No specification fixes it, and it varies with the engine, the browser and the available memory. The order of magnitude sits around ten thousand nested calls. Code that gets close has a design problem anyway: depth should depend on the data, never on luck.


Question

Why does my error trace only show unreadable names?

Because the deployed code is minified: function names were shortened to reduce file size. The fix is to publish a Source map alongside the compiled version, which the monitoring tool uses to recover the original names and line numbers.


Question

Does an async function occupy the stack while it waits?

No. At the await point, the function is removed from the stack and its state is set aside. It returns when the result arrives, which frees the engine for everything else in the meantime. That is exactly what keeps a page responsive during a network call.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.