Skip to main content

Command Palette

Search for a command to run...

Array Flatten in JavaScript: Everything You Need to Know

Arrays inside arrays inside arrays… sounds fun until you actually have to work with them. Let's fix that.

Updated
6 min readView as Markdown
C
Software developer passionate about building scalable web applications with React and backend technologies. I enjoy solving problems, building projects, and sharing my learning with the community.

What Are Nested Arrays?

A normal array looks like this:

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

A nested array is an array that contains other arrays as elements:

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

You'll run into nested arrays more often than you think — API responses, grouped data, tree structures, matrix representations. They're everywhere.


Why Flattening Is Useful

Imagine you're building a shopping cart. Each category returns its own array of items:

const electronics = ["laptop", "phone"];
const clothing    = ["shirt", "jeans"];
const food        = ["rice", "dal"];

const allItems = [electronics, clothing, food];
// [["laptop", "phone"], ["shirt", "jeans"], ["rice", "dal"]]

Now try looping over allItems to render each product — you'll get arrays, not strings. You need a flat list:

// What you want
["laptop", "phone", "shirt", "jeans", "rice", "dal"]

That's exactly what flattening does — it takes a nested array and collapses it into a single-level array.


The Concept: What "Flatten" Really Means

Think of nested arrays like Russian dolls. Flattening is opening each doll and laying everything out on a table.

Input:  [1, [2, 3], [4, [5, [6]]]]

Flatten 1 level:   [1, 2, 3, 4, [5, [6]]]
Flatten 2 levels:  [1, 2, 3, 4, 5, [6]]
Flatten fully:     [1, 2, 3, 4, 5, 6]

The depth controls how many levels deep you unwrap.


Approach 1: Array.flat() — The Modern Way

ES2019 introduced Array.flat(). Clean, readable, built-in.

const arr = [1, [2, 3], [4, [5, 6]]];

arr.flat();     // [1, 2, 3, 4, [5, 6]]  → default depth is 1
arr.flat(2);    // [1, 2, 3, 4, 5, 6]    → depth 2

Flatten completely with Infinity

When you don't know how deeply nested the array is:

const deep = [1, [2, [3, [4, [5]]]]];

deep.flat(Infinity); // [1, 2, 3, 4, 5]

It also removes empty slots

const sparse = [1, , 3, [4, , 6]];
sparse.flat(); // [1, 3, 4, 6]  ← empty slots removed

When to use: Modern browsers and Node.js 11+. This should be your default choice.


Approach 2: reduce() + concat() — The Classic

Before .flat() existed, this was the go-to pattern. You'll see it in interviews a lot.

Flatten one level deep

function flattenOne(arr) {
  return arr.reduce((acc, val) => acc.concat(val), []);
}

flattenOne([1, [2, 3], [4, 5]]); // [1, 2, 3, 4, 5]

Step by step:

Start:       acc = []
Iteration 1: acc = [].concat(1)      → [1]
Iteration 2: acc = [1].concat([2,3]) → [1, 2, 3]
Iteration 3: acc = [1,2,3].concat([4,5]) → [1, 2, 3, 4, 5]

Flatten recursively (any depth)

function flattenDeep(arr) {
  return arr.reduce((acc, val) =>
    Array.isArray(val)
      ? acc.concat(flattenDeep(val))  // recurse if it's an array
      : acc.concat(val),              // otherwise just add it
  []);
}

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

Approach 3: Spread + concat() — One-liner

const arr = [1, [2, 3], [4, 5]];

[].concat(...arr); // [1, 2, 3, 4, 5]

This only works for one level. Using ...arr spreads the outer array as arguments to concat, which handles the inner arrays.

⚠️ Breaks with deeply nested arrays or very large arrays (hits argument limit).


Approach 4: Manual Recursion — Best for Interviews

Writing your own flatten from scratch is the most common interview question. Know this cold.

function flatten(arr, depth = Infinity) {
  const result = [];

  for (const item of arr) {
    if (Array.isArray(item) && depth > 0) {
      // it's an array — go deeper
      result.push(...flatten(item, depth - 1));
    } else {
      // it's a value — add it
      result.push(item);
    }
  }

  return result;
}

flatten([1, [2, [3, [4]]]]);       // [1, 2, 3, 4]       ← full depth
flatten([1, [2, [3, [4]]]], 1);    // [1, 2, [3, [4]]]   ← 1 level
flatten([1, [2, [3, [4]]]], 2);    // [1, 2, 3, [4]]     ← 2 levels

Approach 5: Stack-Based (No Recursion)

Recursion can hit the call stack limit with deeply nested arrays. A stack-based approach avoids that:

function flattenIterative(arr) {
  const stack = [...arr];
  const result = [];

  while (stack.length) {
    const item = stack.pop();

    if (Array.isArray(item)) {
      stack.push(...item);  // push children back onto the stack
    } else {
      result.unshift(item); // add value to front (preserves order)
    }
  }

  return result;
}

flattenIterative([1, [2, [3, [4, 5]]]]); // [1, 2, 3, 4, 5]

This is great to mention in interviews when the interviewer asks "what if the input is extremely deeply nested?"


Common Interview Scenarios

Q1: Flatten only one level

// Input:  [1, [2, 3], [4, [5]]]
// Output: [1, 2, 3, 4, [5]]

arr.flat();                           // built-in
arr.reduce((a, v) => a.concat(v), []); // manual

Q2: Flatten completely

// Input:  [1, [2, [3, [4, [5]]]]]
// Output: [1, 2, 3, 4, 5]

arr.flat(Infinity);   // built-in
flattenDeep(arr);     // recursive

Q3: Flatten and then remove duplicates

const arr = [[1, 2], [2, 3], [3, 4]];

const result = [...new Set(arr.flat())];
// [1, 2, 3, 4]

Q4: Flatten an array of objects' nested arrays

const data = [
  { id: 1, tags: ["js", "node"] },
  { id: 2, tags: ["react", "js"] },
];

const allTags = data.map(item => item.tags).flat();
// ["js", "node", "react", "js"]

// Or using flatMap (map + flat in one step):
const allTags2 = data.flatMap(item => item.tags);
// ["js", "node", "react", "js"]

Q5: Count total elements after flattening (without flattening)

function countElements(arr) {
  return arr.reduce((count, item) =>
    Array.isArray(item) ? count + countElements(item) : count + 1
  , 0);
}

countElements([1, [2, [3, 4]], 5]); // 5

Quick Tip: flatMap() — Map and Flatten Together

flatMap() is equivalent to .map().flat(1) — super useful when your map callback returns arrays:

const sentences = ["Hello World", "JavaScript is fun"];

// Without flatMap
sentences.map(s => s.split(" ")).flat();
// ["Hello", "World", "JavaScript", "is", "fun"]

// With flatMap
sentences.flatMap(s => s.split(" "));
// ["Hello", "World", "JavaScript", "is", "fun"]

When to Use What

Situation Best Choice
Modern codebase, any depth arr.flat(Infinity)
Specific depth needed arr.flat(n)
Map + flatten in one step arr.flatMap()
Interview, write from scratch Recursive flatten()
Extremely deep nesting Stack-based iterative
Legacy code / no ES2019 reduce() + concat()

Summary

Flattening arrays is about collapsing nested structure into a single level. JavaScript gives you .flat() for everyday use, but knowing how to implement it manually — recursively or iteratively — is what separates a good developer from a great one.

The next time you see [[1,2],[3,4]] in an API response, you'll know exactly what to do. 🧩


Found this useful? Share it with someone grinding LeetCode or preparing for their next JavaScript interview. 🚀

More from this blog

C

Chetan Chauhan | Tech Blog | chetan71

45 posts