What Is a Stack Data Structure? LIFO, Examples, and Use Cases
Dev
Last updated on

What Is a Stack Data Structure? LIFO, Examples, and Use Cases


The confusing part of stack data structures is usually not push and pop. It is understanding why the most recent item should come out first.

A stack is a Last In, First Out structure used when recent state matters most, which is why it appears in bracket matching, undo flows, DFS, and call stacks.

This guide covers:

  • the core stack idea and operations
  • when a stack should come to mind naturally
  • bracket matching, undo, DFS, and recursion
  • common beginner mistakes

In short, a stack fits problems where the latest state should be the first one reversed, matched, or revisited.


What is a stack data structure?

A stack is a LIFO structure: Last In, First Out.

The most recently inserted item leaves first. Plates stacked on top of one another are the classic physical analogy.

The key questions are:

  • does the latest state matter most?
  • do we need to undo or backtrack?
  • should matching happen against the most recent opening state?

If yes, a stack is often a natural fit.


When should you use a stack?

1. Undo and back navigation

Editors, browser history, and rollback-style flows often depend on recent-state tracking.

2. Bracket matching

Closing brackets must match the most recently opened bracket.

3. DFS and backtracking

Going deep and then returning in reverse order matches stack behavior closely.

4. Function call flow

The call stack is one of the most important real examples for understanding stacks.


What are the core stack operations?

  • push: add to the top
  • pop: remove from the top
  • peek: inspect the top item
  • isEmpty: check whether it is empty

Performance intuition

Stacks are usually straightforward because they mostly work at one end of the structure.

In JavaScript, array push() and pop() map cleanly to stack behavior, which makes stacks easier to prototype than queues in many cases.


How do you implement a stack?

class Stack {
  constructor() {
    this.items = [];
  }

  push(item) {
    this.items.push(item);
  }

  pop() {
    if (this.items.length === 0) return undefined;
    return this.items.pop();
  }

  peek() {
    return this.items[this.items.length - 1];
  }

  isEmpty() {
    return this.items.length === 0;
  }
}

Example usage:

const stack = new Stack();

stack.push('first');
stack.push('second');
stack.push('third');

console.log(stack.pop());  // third
console.log(stack.peek()); // second

The latest inserted item leaves first, which is the whole point of LIFO.


Stack example 1: why does bracket matching use a stack?

Bracket matching is one of the cleanest examples for why stacks exist.

function isBalanced(text) {
  const stack = [];
  const pairs = {
    ')': '(',
    ']': '[',
    '}': '{'
  };

  for (const ch of text) {
    if (ch === '(' || ch === '[' || ch === '{') {
      stack.push(ch);
      continue;
    }

    if (ch === ')' || ch === ']' || ch === '}') {
      const top = stack.pop();
      if (top !== pairs[ch]) {
        return false;
      }
    }
  }

  return stack.length === 0;
}

When ) appears, it must be checked against the most recent unmatched (, not the oldest one. That is exactly why the stack model fits.


Stack example 2: how does undo use a stack?

Undo flows are also naturally stack-shaped.

This matters because undo is not an arrival-order problem. If the problem is about first-come-first-served handling instead, compare this with the Queue Data Structure Guide.

const undoStack = [];
let currentText = '';

function applyChange(newText) {
  undoStack.push(currentText);
  currentText = newText;
}

function undo() {
  if (undoStack.length === 0) return currentText;
  currentText = undoStack.pop();
  return currentText;
}

applyChange('hello');
applyChange('hello world');
applyChange('hello world!!!');

console.log(undo()); // hello world
console.log(undo()); // hello

The newest saved state is restored first, which is exactly what a stack is meant to do.


Stack example 3: why do DFS and backtracking use a stack?

DFS can be written recursively, but it also maps directly to an explicit stack.

If you want the cleanest contrast with BFS, read this side by side with the traversal section in the Queue Data Structure Guide.

function dfs(graph, start) {
  const visited = new Set();
  const stack = [start];

  while (stack.length > 0) {
    const node = stack.pop();
    if (visited.has(node)) continue;

    visited.add(node);
    console.log('visit:', node);

    for (const next of graph[node].reverse()) {
      if (!visited.has(next)) {
        stack.push(next);
      }
    }
  }
}

Because the most recently added node is processed next, traversal goes deeper before it broadens, which is the defining behavior of DFS.


How are recursion and the call stack connected?

Stacks also matter for understanding function calls.

function countdown(n) {
  if (n === 0) return;
  console.log(n);
  countdown(n - 1);
}

Each call pushes a new frame, and completion unwinds them in reverse order. That is why recursion feels much less mysterious once the call stack idea is clear.


Stack vs queue

  • stack: latest item leaves first
  • queue: earliest item leaves first

If the real need is ranked retrieval rather than either of those two rules, the Sorted Set Guide is the better comparison.

Stack vs recursion

Recursion is a technique. A stack is a structure. They are related because recursive calls use the call stack.

Stack vs array

An array is a storage structure. A stack is a usage rule. Arrays can implement stacks, but they are not the same concept.


Common beginner mistakes with stacks

1. Overwriting state instead of storing history

That makes undo and rollback behavior difficult to build.

2. Learning DFS without tying it to stack behavior

The connection helps the algorithm make sense instead of feeling memorized.

3. Treating recursion like magic

It gets much easier once you picture stack frames being pushed and popped.

4. Mixing stacks and queues together

Both add and remove items, but the removal rule is the defining difference.


What kinds of problems should make you think of a stack?

Stacks are a strong candidate when:

  1. the latest state matters most
  2. undo or backtracking is required
  3. matching must happen against the most recent open state
  4. control flow goes deep and then returns in reverse order

FAQ

Q. Why are stacks easy to implement with arrays?

Because many languages make append and remove-at-end operations straightforward and efficient enough for stack behavior.

Q. Should I learn stacks before recursion?

Usually yes. Recursion becomes much easier once the stack idea is intuitive.

Q. Where do stacks appear in practice?

Undo systems, parsers, DFS, call flow, browser history, and many backtracking problems.


Start Here

Continue with the core guides that pull steady search traffic.