Stack
A stack is a Last-In, First-Out (LIFO) data structure: you can only add elements to the top and remove elements from the top. Think of it like a stack of plates.
Explanation
A stack has two core operations: push (add an item to the top) and pop (remove the item from the top). Both are O(1). A peek or top operation returns the top element without removing it. An isEmpty check is usually included. That's the complete interface — stacks are intentionally restrictive, and that restriction is what makes them useful. The most important real-world stack you work with daily is the call stack. Every time your program calls a function, a stack frame containing that function's local variables and return address is pushed onto the call stack. When the function returns, its frame is popped and execution resumes in the calling function. "Maximum call stack size exceeded" is what happens when recursion runs too deep — you've pushed too many frames and run out of memory. Browser DevTools show the call stack when you hit a breakpoint or error. Every entry in that list is a stack frame. Understanding this is the key to reading stack traces when debugging: the bottom of the stack trace is where execution started, the top is where the error occurred. Beyond the call stack, stacks appear in: undo/redo systems (each action is pushed; undo pops the last action), syntax validation (a balanced parentheses checker uses a stack to track opened brackets), expression evaluation, depth-first search (either implicitly via recursion or explicitly with a stack), and browser history (Back navigates to the previous page by conceptually popping the history stack).
Code Example
javascript// Stack using a JavaScript array (push/pop already LIFO)
class Stack {
#items = [];
push(item) { this.#items.push(item); }
pop() { return this.#items.pop(); } // returns undefined if empty
peek() { return this.#items.at(-1); }
isEmpty() { return this.#items.length === 0; }
size() { return this.#items.length; }
}
// Real use: balanced parentheses checker
function isBalanced(str) {
const stack = new Stack();
const pairs = { ')': '(', ']': '[', '}': '{' };
for (const ch of str) {
if ('([{'.includes(ch)) stack.push(ch);
else if (')]}'.includes(ch)) {
if (stack.pop() !== pairs[ch]) return false;
}
}
return stack.isEmpty();
}
console.log(isBalanced('({[]})')); // true
console.log(isBalanced('([)]')); // false
Why It Matters for Engineers
The call stack is not an abstraction — it's the actual mechanism that makes function calls work in every language. Understanding it explains stack overflow errors, tail call optimization, why deeply recursive functions fail, and how debuggers show you execution state. This is foundational knowledge every software engineer needs, not optional trivia. Stacks also appear constantly in algorithm problems (valid parentheses, next greater element, monotonic stack patterns) and system design contexts (undo/redo, browser history, transaction rollback). Recognizing "this is a stack problem" is a core pattern-matching skill.
Related Terms
Learn This In Practice
Go deeper with the full module on Beyond Vibe Code.
Data Structures Fundamentals → →