Quick Answer

A stack is last in, first out: the most recently added item is the first one removed, like a pile of plates. A queue is first in, first out: items leave in the order they arrived, like a line at a counter. Both offer O(1) insertion and removal. Use a stack when you need to reverse order or backtrack — undo, browser back, function calls. Use a queue when order must be preserved — print jobs, task scheduling, breadth-first search.

The One Difference That Defines Both

Both are simple collections with a rule about which item you are allowed to remove next. That rule is the whole difference.

A stack is LIFO — last in, first out. Picture a pile of plates. You add to the top and take from the top. The plate you put down most recently is the one you pick up first, and the plate at the bottom stays there until everything above it is gone.

push(1) → [1]
push(2) → [1, 2]
push(3) → [1, 2, 3]
pop()   → returns 3, leaves [1, 2]        LAST in, FIRST out

A queue is FIFO — first in, first out. Picture a line at a ticket counter. People join at the back and are served from the front, in the order they arrived.

enqueue(1) → [1]
enqueue(2) → [1, 2]
enqueue(3) → [1, 2, 3]
dequeue()  → returns 1, leaves [2, 3]     FIRST in, FIRST out

Notice what this does to ordering. A stack reverses whatever you put into it. A queue preserves the order. Almost every practical choice between them comes down to which of those you want.

Where Stacks Show Up in Real Code

You use stacks constantly, usually without building one.

The call stack. Every time a function calls another, the current one is pushed and paused. When the inner call returns, it is popped and execution resumes. This is why a stack trace reads bottom-up, and why runaway recursion produces a literal "stack overflow" — you pushed more frames than the stack could hold.

Undo. Each action is pushed as you work. Ctrl+Z pops the most recent one, which is exactly the behaviour you want: undo should reverse the last thing you did, not the first.

Browser back button. Pages are pushed as you navigate; back pops the most recent.

Bracket matching. The standard interview problem, and a real technique used by every code editor. Push each opening bracket; on a closing bracket, pop and check it matches. If the stack is empty when you need to pop, or non-empty at the end, the brackets are unbalanced.

def is_balanced(s):
    pairs = {')': '(', ']': '[', '}': '{'}
    stack = []
    for ch in s:
        if ch in '([{':
            stack.append(ch)
        elif ch in pairs:
            if not stack or stack.pop() != pairs[ch]:
                return False
    return not stack        # anything left over is unclosed

Depth-first search. Exploring as far as possible before backtracking is naturally a stack, whether you build one explicitly or use recursion, which is a stack in disguise.

Where Queues Show Up in Real Code

Queues appear wherever fairness or arrival order matters.

Print jobs and task schedulers. The document you sent first prints first. Using a stack here would mean the last person to hit print jumps the line, which is exactly the complaint you would expect.

Breadth-first search. Exploring a graph level by level requires a queue. This is what finds the shortest path in an unweighted graph, and swapping the queue for a stack silently turns it into a depth-first search that no longer guarantees the shortest route.

Message and job queues. Systems like RabbitMQ and SQS exist to hold work in arrival order until a worker is free — the same idea at infrastructure scale.

Request handling and buffering. Incoming requests wait in order rather than being dropped, and keystrokes buffer so nothing is lost when the application is briefly busy.

A priority queue is the common variation worth knowing: items leave in priority order rather than arrival order. It powers Dijkstra's algorithm and hospital triage alike, and it is usually implemented with a heap rather than a plain list.

Implementing Them Correctly

A stack is easy in any language, because adding and removing at the end of a dynamic array is already O(1).

stack = []
stack.append(x)     # push, O(1)
top = stack.pop()   # pop,  O(1)

A queue is where people write accidentally slow code. The obvious version uses a list and removes from the front — and that is O(n), because every remaining element shifts left on each removal.

# WRONG for large data: pop(0) is O(n)
queue = []
queue.append(x)
item = queue.pop(0)          # shifts everything left, every time

# Right: a deque removes from either end in O(1)
from collections import deque
queue = deque()
queue.append(x)              # enqueue, O(1)
item = queue.popleft()       # dequeue, O(1)

This turns an O(n) loop into an O(n squared) one without any obvious sign, and it is a common reason a correct BFS times out on large inputs. In Java use ArrayDeque rather than LinkedList; in JavaScript, Array.shift() has the same O(n) problem as Python's pop(0).

Choosing Between Them

Ask one question: does the most recent item matter most, or the oldest?

If you need to reverse, backtrack, or undo — anything where the latest action should be handled first — that is a stack. If arrival order must be respected, or you are exploring outward level by level, that is a queue.

The clearest illustration is graph traversal, where the only difference between the two algorithms is the container. Swap a stack for a queue in the same code and depth-first becomes breadth-first. Same loop, same visited set, completely different traversal order and different guarantees about the path you find.

Both give O(1) insertion and removal, so performance is rarely the deciding factor. Order semantics are.

Frequently Asked Questions

What does LIFO and FIFO mean? LIFO is last in, first out — the most recently added item is removed first, which is how a stack behaves. FIFO is first in, first out — items are removed in arrival order, which is how a queue behaves.
Is recursion a stack? Yes. Every pending function call sits on the call stack until it returns, in last-in-first-out order. That is why deep recursion causes a stack overflow, and why any recursive algorithm can be rewritten iteratively using an explicit stack.
Why is pop(0) bad for a queue in Python? Removing the first element of a list shifts every remaining element one position left, making it O(n). Inside a loop that turns an O(n) algorithm into O(n squared). Use collections.deque and popleft(), which is O(1).
What is a priority queue? A queue where items leave in priority order rather than arrival order. It is usually built on a heap, giving O(log n) insertion and removal. Dijkstra's shortest-path algorithm and most task schedulers depend on it.
Can I use a stack for BFS? No — swapping the queue for a stack turns breadth-first search into depth-first search. BFS explores level by level, which is what guarantees the shortest path in an unweighted graph, and that guarantee comes directly from FIFO ordering.