Two functions both work perfectly on your laptop with 100 items. In production, with a million items, one returns in a blink and the other takes hours. Big O is how you predict that before it happens.
The one idea behind Big O
Big O answers a single question: if the input gets bigger, how much more work does this do? It doesn't measure seconds — those depend on the machine. It measures the shape of growth.
- Double the input, same work? →
O(1), constant. - Double the input, double the work? →
O(n), linear. - Double the input, four times the work? →
O(n²), quadratic.

The growth playground
Toggle the curves, drag n, then try the reality check at n = 1,000,000. Assume your computer does one operation per microsecond.
O(1)1
O(log n)3
O(n)8
O(n log n)24
O(n²)64
O(2ⁿ)256
Reality check — 1 operation = 1 µs
Bars use a logarithmic scale — otherwise O(1) would be invisible.
At small n everything is fast. At real-world n, only the shape of the curve matters.
Meet the family
O(1) — constant
Reading array[5] or map.get(key). Same cost for 10 items or 10 million.
O(log n) — logarithmic
Each step throws away half of what's left. Binary search finds an item among 1,000,000 sorted items in about 20 steps. Database indexes (B-trees) live here.
O(n) — linear
One pass over the data: .map(), .filter(), .find(), summing a list.
O(n log n) — linearithmic
The speed limit for comparison-based sorting. Array.prototype.sort in modern engines uses TimSort, which is O(n log n).
O(n²) — quadratic
A loop inside a loop over the same data. Fine for 100 items; painful for 100,000.
O(2ⁿ) — exponential
Every extra item doubles the work: naive recursive Fibonacci, trying every subset. Unusable beyond tiny n.
Quick check
Binary search on 1,000,000 sorted items needs about how many comparisons?
How to find the Big O of your code
- Count the loops over the input. One loop → n. Nested → n × n.
- Sequential steps add, nested steps multiply. O(n) then O(n) = O(2n) = O(n).
- Drop constants and smaller terms. O(n² + n + 100) → O(n²).
- Watch hidden loops.
includes,indexOf,findand spreading arrays are loops too.
Here is the most common accidental O(n²) in JavaScript — and its fix:
// O(n²): .includes() scans the whole result array every time
function slowUnique(items) {
const result = [];
for (const item of items) {
if (!result.includes(item)) result.push(item);
}
return result;
}
// O(n): a Set lookup is O(1) on average
const fastUnique = (items) => [...new Set(items)];Quick check
What is the Big O of: for (a of users) for (b of orders) if (a.id === b.userId) …
What it means in real apps
- Search-as-you-type over thousands of items: pre-index or debounce instead of filtering everything per keystroke.
- Rendering huge lists: virtualise — render only the ~20 visible rows, not 10,000.
- Databases: an index turns an O(n) table scan into an O(log n) lookup.


