Skip to main content

Command Palette

Search for a command to run...

Array Flatten in JavaScript

Published
10 min read
Array Flatten in JavaScript

In JavaScript, arrays can nest inside other arrays, sometimes several levels deep. And while that structure can make sense when data is first collected or received, there are plenty of moments where you just need everything laid out flat in one clean, simple list.

That's what array flattening is. And by the end of this article, you'll not only understand what it means and why it matters, you'll have multiple ways to do it, and you'll know which way to reach for depending on the situation.

1. What Are Nested Arrays

Let's start from the beginning, because this concept is easier to feel than to define.

A normal array looks like this:

let fruits = ["apple", "banana", "mango"];

Simple. One level. Everything is right there.

Now imagine you're collecting the weekly shopping list from three different family members, and each person gave you their list separately:

let shoppingList = [
  ["apple", "banana"],           // Mom's list
  ["milk", "eggs", "butter"],    // Dad's list
  ["chips", "juice"]             // Your list
];

This is a nested array, an array that contains other arrays as its elements. Each inner array is sitting inside the outer one, like folders inside a folder.

It gets deeper too. Real-world data, especially from APIs can come in multiple levels of nesting:

let deepList = [
  ["apple", ["green apple", "red apple"]],
  ["milk", ["full fat", ["skimmed", "semi-skimmed"]]],
];

Now you've got arrays inside arrays inside arrays. Opening one box just reveals another.

2. Why Flattening Arrays Is Useful

Here's a real situation that every JavaScript developer eventually runs into.

You're building a recipe app. Each cuisine category has a list of dishes. Your data looks like this:

let menuByCategory = [
  ["Butter Chicken", "Palak Paneer", "Dal Makhani"],   // Indian
  ["Pasta Carbonara", "Risotto", "Tiramisu"],           // Italian
  ["Sushi", "Ramen", "Tempura"]                         // Japanese
];

This structure makes total sense for organizing the menu. But now you need to:

  • Search across all dishes at once

  • Display every dish in a single scrollable list

  • Count the total number of dishes

  • Sort all dishes alphabetically

Suddenly that nicely organized nested structure is working against you. You can't just do menuByCategory.includes("Ramen") — it won't work because "Ramen" is buried inside an inner array.

What you actually need is this:

["Butter Chicken", "Palak Paneer", "Dal Makhani", "Pasta Carbonara", "Risotto", "Tiramisu", "Sushi", "Ramen", "Tempura"]

One flat list. Everything accessible. Easy to loop, search, sort, and count.

That transformation, from nested to flat is array flattening.

Other common real-world moments where flattening becomes essential:

  • API responses that return grouped data (orders grouped by date, messages grouped by chat)

  • Form data collected in sections that needs to be processed as one list

  • Tag systems where each post has an array of tags, and you want all tags across all posts

  • File paths grouped by directory that you need as one flat list

3. The Concept of Flattening (Step by Step)

Before jumping into code, let's understand what flattening actually does at each step — because this is the kind of thinking that helps you in interviews too. Take this simple nested array: js

let nested = [1, [2, 3], [4, [5, 6]]];

Visually, it looks like this:

[ 1,  [ 2, 3 ],  [ 4, [ 5, 6 ] ] ]
  ↑       ↑            ↑
plain   inner        inner array
number  array      with ANOTHER
                   array inside

Flattening by one level means: "Open the outermost arrays and pull their contents up by one level."

Before:  [ 1,  [2, 3],  [4, [5, 6]] ]
After:   [ 1,   2,  3,   4,  [5, 6] ]

Notice that [5, 6] is still nested, because it was two levels deep, and we only flattened one level. The 4 came up, but [5, 6] is still wrapped.

Flattening completely (infinite depth) means: "Keep opening arrays until there are no more arrays inside , just raw values."

Before:  [ 1,  [2, 3],  [4, [5, 6]] ]
After:   [ 1,   2,  3,   4,   5,  6 ]

Now every value is at the same level. Clean, flat, accessible.

4. Different Approaches to Flatten Arrays

Now let's get into the actual code. There are several ways to flatten arrays in JavaScript, and each has its own personality, some are modern and elegant, some are manual and educational. A well-rounded developer knows all of them.

Approach 1 --> Array.flat() : The Modern, Built-in Way

Introduced in ES2019, .flat() is the cleanest solution and the one you'll reach for most often in real projects.

let nested = [1, [2, 3], [4, [5, 6]]];

nested.flat();      // [1, 2, 3, 4, [5, 6]]  — one level deep (default)
nested.flat(2);     // [1, 2, 3, 4, 5, 6]    — two levels deep
nested.flat(Infinity); // [1, 2, 3, 4, 5, 6] — completely flat, no matter how deep

Done. One method call, and you've got your clean list ready to display or process.

The one thing to know: The number you pass in flat(1), flat(2), flat(Infinity), is the depth. If you're unsure how deep your nesting goes, flat(Infinity) is your safest thing to add.

Approach 2 --> flatMap() : Flatten While You Transform

flatMap() is like .map() and .flat() had a child together. It transforms each element and flattens the result, all in one pass.

Here's a practical example. Say you have a list of sentences, and you want all individual words across all sentences as one flat array:

let sentences = ["Hello world", "JavaScript is fun", "Modules are great"];

let words = sentences.flatMap(sentence => sentence.split(" "));
// ["Hello", "world", "JavaScript", "is", "fun", "Modules", "are", "great"]

Compare this to doing it in two steps:

// Without flatMap — two operations
let words = sentences.map(sentence => sentence.split(" ")).flat();

flatMap() does both in one cleaner step.

Another real example : expanding a list of orders where each order has multiple items:

let orders = [
  { id: 1, items: ["pizza", "cola"] },
  { id: 2, items: ["burger", "fries", "milkshake"] },
];

let allItems = orders.flatMap(order => order.items);
// ["pizza", "cola", "burger", "fries", "milkshake"]

Approach 3 --> reduce() : The Manual, Old-School Way

Before .flat() existed, developers built their own flattening logic using reduce(). It's worth understanding this approach because it teaches you exactly what flattening does under the hood.

let nested = [1, [2, 3], [4, 5]];

let flat = nested.reduce((accumulator, current) => {
  return accumulator.concat(current);
}, []);

// [1, 2, 3, 4, 5]

Think of reduce() here as going through each element one by one and asking: "Should I add this directly to my result list, or should I open it up first?"

The accumulator is your growing flat list. concat either adds a value directly, or spreads an inner array's items in.

For deeply nested arrays, you'd need a recursive version:

function flattenDeep(arr) {
  return arr.reduce((acc, current) => {
    if (Array.isArray(current)) {
      return acc.concat(flattenDeep(current));  // go deeper
    } else {
      return acc.concat(current);               // add value directly
    }
  }, []);
}

flattenDeep([1, [2, [3, [4]]]]);
// [1, 2, 3, 4]

Step by step, this is what happens:

  1. See 1 : it's not an array, add it directly → [1]

  2. See [2, [3, [4]]] : it IS an array, go inside it recursively

  3. See 2 : add directly → [1, 2]

  4. See [3, [4]] : array again, go deeper

  5. See 3 : add directly → [1, 2, 3]

  6. See [4] : array again, go deeper

  7. See 4 : add directly → [1, 2, 3, 4]

Approach 4 --> Spread + concat : Quick One-Liner for One Level

For a quick, shallow flatten — just one level deep — this classic trick still works and is fun to know:

let nested = [[1, 2], [3, 4], [5, 6]];

let flat = [].concat(...nested);
// [1, 2, 3, 4, 5, 6]

The spread operator ...nested unpacks the outer array, and concat joins everything together. It's a clever trick, but it only works for one level, so don't reach for this with deeply nested data.

5. Common Interview Scenarios

Array flattening is a beloved interview topic — and for good reason. It tests whether you understand arrays, recursion, and problem-solving thinking all at once. Here are the scenarios you're most likely to face.

Scenario 1 --> "Write a flatten function without using .flat()"

This is the classic. The interviewer wants to see your manual logic, not just your knowledge of built-in methods.

js

function flatten(arr) {
  let result = [];

  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      // It's an array : flatten it and merge into result
      let inner = flatten(arr[i]);
      result = result.concat(inner);
    } else {
      // It's a plain value : add it directly
      result.push(arr[i]);
    }
  }

  return result;
}

flatten([1, [2, [3, [4]]]]);
// [1, 2, 3, 4]

Walk through this out loud in an interview. Comment your thinking. Interviewers care about how you reason, not just whether the output is right.


Scenario 2 --> "Flatten only up to N levels deep"

This tests whether you understand the depth parameter concept.

js

function flattenToDepth(arr, depth) {
  if (depth === 0) return arr;  // stop going deeper

  let result = [];

  for (let item of arr) {
    if (Array.isArray(item) && depth > 0) {
      result = result.concat(flattenToDepth(item, depth - 1));
    } else {
      result.push(item);
    }
  }

  return result;
}

flattenToDepth([1, [2, [3, [4]]]], 2);
// [1, 2, 3, [4]]   — stopped at depth 2, so [4] stays nested

The key insight here: each recursive call reduces the depth by 1. When depth reaches 0, stop digging.


Scenario 3 --> "Get all unique tags from a list of blog posts"

This is a real-world application question that tests whether you can connect flattening to actual product logic.

let posts = [
  { title: "Intro to JS",     tags: ["javascript", "beginners"] },
  { title: "CSS Grid Guide",  tags: ["css", "layout", "beginners"] },
  { title: "Node.js Basics",  tags: ["javascript", "node", "backend"] },
];

let allTags = posts.flatMap(post => post.tags);
// ["javascript", "beginners", "css", "layout", "beginners", "javascript", "node", "backend"]

let uniqueTags = [...new Set(allTags)];
// ["javascript", "beginners", "css", "layout", "node", "backend"]

This kind of question tests three things at once: flatMap, data transformation thinking, and deduplication with Set. If you nail this in an interview, you make a strong impression.


Scenario 4 --> "What's the output?" (Tricky Edge Case)

Interviewers sometimes throw a tricky output question to test your depth understanding:

console.log([1, [2, [3]]].flat());
console.log([1, [2, [3]]].flat(1));
console.log([1, [2, [3]]].flat(Infinity));

Do you know the answers without running the code?

// [1, 2, [3]]     — default depth is 1, so [3] is still nested
// [1, 2, [3]]     — same thing, explicit depth 1
// [1, 2, 3]       — Infinity goes all the way

Conclusion

Nested arrays are everywhere in real JavaScript work, in API responses, in grouped data, in collected form inputs. And while nesting makes sense for organizing data, flattening is what makes that data usable.

Here's how to think about it going forward:

  • Reach for .flat() in everyday code, it's clean and purpose-built

  • Use flatMap() when you're transforming and flattening in the same step

  • Understand reduce() with recursion for interviews and custom logic

  • Know the depth parameter : it's the key detail that separates a surface-level answer from a confident one