Array Flatten JavaScript: flat() vs Recursion vs Stack

JavaScript's flat() method looks deceptively simple. But when your data structures get weird—and they will—you need to know what's actually happening under the hood.

JavaScript's Array.flat() Is Elegant. But Your Nested Data Might Need Something Meaner. — theAIcatchup

Key Takeaways

  • Array.flat() is clean and modern, but only works in ES2019+ browsers—legacy environments need alternatives
  • Recursion is intuitive but crashes on deeply nested arrays due to call stack limits
  • Stack-based iteration handles arbitrary nesting depth without overhead and is often fastest for large datasets

According to Stack Overflow, array flattening questions rack up thousands of views per month. Real developers hit this problem constantly. And yet, most of them reach for Array.flat() without thinking about whether it’s actually the right tool.

Here’s the thing: flat() is a marvel of API design. It’s clean. It reads like English. And for most cases, it solves the problem in one line. But elegance can be a trap.

What You’re Actually Dealing With

A nested array is just an array containing other arrays. Could be one level deep, could be ten. Could theoretically be infinite.

[5, 6, [7, 8]]
[5, 6, [7, 8, [8, 9]]]

That second example? If you’re processing real-world data—API responses from third-party services, JSON from databases, configuration files that have been hand-edited one too many times—nested arrays are everywhere. They’re also deeply annoying to work with.

Flatten them once, and suddenly you’re processing [5, 6, 7, 8, 8, 9] like a normal person. But the journey from nested chaos to flat bliss matters more than you’d think.

The Easy Path: Array.flat() and When It Works

The flat() method creates a new array with all sub-array elements concatenated into it recursively up to the specified depth.

That’s the MDN definition. In English: it does what you want, most of the time.

let arr = [1, 2, [3, 4], [7, 8, [9, 10]]];
console.log(arr.flat(Infinity));
// Output: [1, 2, 3, 4, 7, 8, 9, 10]

Pass Infinity and you get complete flattening. Pass a number—say, 2—and you only flatten that many levels deep.

let arr1 = [1, 2, [3, 4], [7, 8, [9, 10, [5, 6]]]];
console.log(arr1.flat(2));
// Output: [1, 2, 3, 4, 7, 8, 9, 10, [5, 6]]

Notice something? The innermost [5, 6] stayed nested because we only flattened two levels. This is actually useful when you want to control the depth. And if you’re working with data you understand—API responses with a known structure, for example—this selective approach beats full flattening every single time.

But here’s where JavaScript gets weird: flat() was added in 2019. If you’re supporting legacy browsers (and some of us still are, thanks enterprise), it won’t exist. Your code explodes. Your app crashes at 3 AM. Your manager asks why you didn’t just write a for loop.

Why Recursion Feels Right (But Costs You)

Recursion is the classic approach. Write a function that calls itself. It’s elegant, intuitive, and makes computer science professors nod approvingly.

const array = [[5, 6, [4, 5]], [7, 8], 9, 10];
let result = [];

function flattenArray(arr) {
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      flattenArray(arr[i]); // recursive call
    } else {
      result.push(arr[i]);
    }
  }
}

flattenArray(array);
console.log(result);
// Output: [5, 6, 4, 5, 7, 8, 9, 10]

It works. It’s readable. You can trace through it mentally. But—and this is a big but—recursion eats call stack space. For deeply nested arrays (think 5,000 levels), you hit JavaScript’s maximum call stack size and the whole thing fails. Your code doesn’t just slow down. It breaks.

So when do you use recursion? When you know your nesting depth is reasonable. When you’re in an interview and the interviewer wants to see your thinking. When you’re writing something quick and the data is tame.

But when your data comes from the wild? When some API decides to nest things eight levels deep? Recursion becomes a liability dressed up as elegance.

The Approach Nobody Talks About: Stacks

Here’s the weird one. The iterative approach using a stack.

let arr1 = [1, 2, [3, 4], [7, 8, [9, 10, [5, 6]]]];
let stack = [...arr1];
let result = [];

while (stack.length) {
  let item = stack.pop();
  if (Array.isArray(item)) {
    stack.push(...item);
  } else {
    result.push(item);
  }
}

console.log(result.reverse());
// Output: [1, 2, 3, 4, 7, 8, 9, 10, 5, 6]

Why does this work? You’re using JavaScript’s built-in stack (the call stack is replaced with an actual array-based stack). You pop items off. If it’s an array, you unpack it back onto the stack. If it’s a value, you capture it.

The kicker: no recursion overhead. No call stack limits. You can flatten arbitrarily deep data structures without fear. It’s faster on massive datasets. It’s also about ten times less intuitive, which is why most people never write it.

Which One Should You Actually Use?

Flat() for modern code you control? Use it. It’s clear, it’s tested, it’s built-in.

Legacy browser support? Stack-based iteration.

Interviews or small datasets? Recursion, but with a note about stack limits.

Production systems handling unknown data shapes? Stack wins. Always.

The truth is less romantic than “pick the most elegant solution.” The truth is: pick the solution that doesn’t break when reality gets weird. And reality gets weird more often than we’d like to admit.

FAQ

What does Array.flat() do in JavaScript? It creates a new array with all nested sub-arrays flattened to a specified depth. Pass Infinity to flatten completely, or a number (like 2) to flatten only that many levels.

Is recursion safe for deeply nested arrays? No. JavaScript has a maximum call stack size (usually around 10,000 calls). For deeply nested data, you’ll hit “Maximum call stack size exceeded.” Use iteration or stack-based approaches instead.

When should I use a stack-based approach instead of Array.flat()? When you need to support older browsers, handle extremely deep nesting, or need maximum performance. Stack-based iteration is faster and won’t crash on large datasets.


🧬 Related Insights

Elena Vasquez
Written by

Senior editor and generalist covering the biggest stories with a sharp, skeptical eye.

Frequently asked questions

🧬 Related Insights?
- **Read more:** [npm's Security Crisis Is Real—And GitHub Isn't Fixing It Fast Enough](https://opensourcebeat.com/article/npms-security-crisis-is-realand-github-isnt-fixing-it-fast-enough/) - **Read more:** [Azure Kubernetes Service: Why Your Cost Optimization Strategy Is Probably Broken](https://opensourcebeat.com/article/azure-kubernetes-service-why-your-cost-optimization-strategy-is-probably-broken/)

Worth sharing?

Get the best AI stories of the week in your inbox — no noise, no spam.

Originally reported by Dev.to

Stay in the loop

The week's most important stories from theAIcatchup, delivered once a week.