JS Array Flat Method: Flatten Nested Arrays Fast

Master the JavaScript flat() method for flattening nested arrays. Covers syntax, depth control, removing holes, comparison with flatMap and reduce, real-world patterns, and common mistakes.

JavaScriptbeginner
12 min read

The flat() method creates a new array with all sub-array elements pulled up to a specified depth. A single call to flat() turns [[1, 2], [3, 4]] into [1, 2, 3, 4]. It also removes empty holes from sparse arrays. Introduced in ES2019, flat() replaces the verbose reduce() + concat() flattening patterns that developers used for years.

What flat() Does

flat() takes nested arrays and collapses them by the specified depth level:

javascriptjavascript
const nested = [[1, 2], [3, 4], [5, 6]];
 
const flat = nested.flat();
console.log(flat); // [1, 2, 3, 4, 5, 6]
 
// Original unchanged
console.log(nested); // [[1, 2], [3, 4], [5, 6]]

Syntax

javascriptjavascript
const newArray = array.flat(depth)
ParameterDescriptionDefault
depthHow many levels of nesting to flatten1

Return Value

A new array with sub-arrays flattened to the specified depth. The original array is never modified.

Depth Control

Default Depth (1)

javascriptjavascript
const data = [1, [2, 3], [4, [5, 6]]];
 
const flat1 = data.flat();      // depth = 1 (default)
console.log(flat1); // [1, 2, 3, 4, [5, 6]]
// One level flattened: [2, 3] spread out, but [5, 6] inside [4, ...] stays nested

Depth 2

javascriptjavascript
const data = [1, [2, [3, [4, [5]]]]];
 
const flat2 = data.flat(2);
console.log(flat2); // [1, 2, 3, [4, [5]]]

Infinity (Flatten Everything)

javascriptjavascript
const deeplyNested = [1, [2, [3, [4, [5, [6, [7]]]]]]];
 
const fullyFlat = deeplyNested.flat(Infinity);
console.log(fullyFlat); // [1, 2, 3, 4, 5, 6, 7]
DepthInputResult
1[1, [2, [3]]][1, 2, [3]]
2[1, [2, [3]]][1, 2, 3]
Infinity[1, [2, [3, [4]]]][1, 2, 3, 4]
Use Infinity Carefully

Passing Infinity flattens every level of nesting regardless of depth. This is convenient but can hide bugs if deeply nested structures exist where nesting carries meaning (like tree data). Use a specific depth when you know the expected structure.

Removing Sparse Array Holes

flat() also removes empty slots from sparse arrays:

javascriptjavascript
const sparse = [1, , 3, , 5];
console.log(sparse.flat()); // [1, 3, 5]
 
const nestedSparse = [1, , [2, , 3], [, 4]];
console.log(nestedSparse.flat()); // [1, 2, 3, 4]

This is a convenient side effect: flat() removes sparse array holes during flattening:

javascriptjavascript
const holey = [1, , 2, , 3];
const clean = holey.flat(); // Removes holes and returns [1, 2, 3]
console.log(clean); // [1, 2, 3]

Real-World Patterns

Merging API Responses

When multiple API calls return arrays and you need a single combined list:

javascriptjavascript
const page1 = [{ id: 1, name: "Widget" }, { id: 2, name: "Gadget" }];
const page2 = [{ id: 3, name: "Gizmo" }, { id: 4, name: "Doohickey" }];
const page3 = [{ id: 5, name: "Thingamajig" }];
 
const allPages = [page1, page2, page3];
const allProducts = allPages.flat();
console.log(allProducts.length); // 5

Extracting Nested Tags

javascriptjavascript
const articles = [
  { title: "React Basics", tags: ["React", "Frontend"] },
  { title: "Node.js Guide", tags: ["Node.js", "Backend"] },
  { title: "Full Stack", tags: ["React", "Node.js", "Full Stack"] },
];
 
const allTags = articles.map(a => a.tags).flat();
console.log(allTags);
// ["React", "Frontend", "Node.js", "Backend", "React", "Node.js", "Full Stack"]
 
// Remove duplicates
const uniqueTags = [...new Set(allTags)];
console.log(uniqueTags);
// ["React", "Frontend", "Node.js", "Backend", "Full Stack"]

This pattern (map then flat) is so common that JavaScript provides flatMap() as a single-method shortcut.

Processing Nested File Structures

javascriptjavascript
const fileSystem = [
  { folder: "src", files: ["index.ts", "app.ts"] },
  { folder: "lib", files: ["utils.ts", "helpers.ts", "constants.ts"] },
  { folder: "tests", files: ["app.test.ts"] },
];
 
const allFiles = fileSystem.map(dir => 
  dir.files.map(f => `${dir.folder}/${f}`)
).flat();
 
console.log(allFiles);
// ["src/index.ts", "src/app.ts", "lib/utils.ts", "lib/helpers.ts", "lib/constants.ts", "tests/app.test.ts"]

Normalizing Inconsistent API Data

javascriptjavascript
// Some entries are arrays, some are single values
const rawInput = ["alice", ["bob", "carol"], "dave", ["eve", "frank", "grace"]];
 
const normalized = rawInput.flat();
console.log(normalized);
// ["alice", "bob", "carol", "dave", "eve", "frank", "grace"]

flat() vs reduce() + concat()

Before flat() existed, flattening required manual iteration:

javascriptjavascript
const nested = [[1, 2], [3, 4], [5, 6]];
 
// Old way: reduce + concat
const flatOld = nested.reduce((acc, arr) => acc.concat(arr), []);
 
// New way: flat()
const flatNew = nested.flat();
 
// Both produce: [1, 2, 3, 4, 5, 6]

For deep flattening, the old recursive approach was even more verbose:

javascriptjavascript
// Old way: recursive function
function deepFlatten(arr) {
  return arr.reduce((acc, val) => {
    return acc.concat(Array.isArray(val) ? deepFlatten(val) : val);
  }, []);
}
 
// New way
const result = deeplyNested.flat(Infinity);
ApproachReadabilityLines of CodeDeep Flattening
flat()Excellent1flat(Infinity)
flat(depth)Excellent1flat(2), flat(3), etc.
reduce() + concatFair1 (single level only)Requires recursion
Recursive functionPoor5+Manual implementation

flat() vs flatMap()

flat() only flattens. flatMap() maps then flattens one level:

javascriptjavascript
const sentences = ["Hello world", "Good morning", "Nice day"];
 
// map + flat (two passes)
const words1 = sentences.map(s => s.split(" ")).flat();
 
// flatMap (one pass)
const words2 = sentences.flatMap(s => s.split(" "));
 
// Both: ["Hello", "world", "Good", "morning", "Nice", "day"]
MethodMapsFlattensMax Depth
flat()NoYesAny (configurable)
flatMap()YesYes1 (always)
map().flat()YesYesAny (configurable)

Common Mistakes

Expecting flat() to mutate the original:

javascriptjavascript
const data = [[1, 2], [3, 4]];
 
// flat() returns a NEW array
data.flat();
console.log(data); // [[1, 2], [3, 4]] — unchanged!
 
// Fix: assign the result
const result = data.flat();
console.log(result); // [1, 2, 3, 4]

Using flat() when flatMap() is more appropriate:

javascriptjavascript
const users = [
  { name: "Alice", hobbies: ["reading", "hiking"] },
  { name: "Bob", hobbies: ["gaming", "cooking"] },
];
 
// Two-pass approach (wasteful intermediate array)
const hobbies1 = users.map(u => u.hobbies).flat();
 
// Better: single-pass with flatMap()
const hobbies2 = users.flatMap(u => u.hobbies);

Using the wrong method to remove sparse holes:

javascriptjavascript
const sparse = [1, , 3, , 5];
 
// flat() removes holes reliably
const clean = sparse.flat();
console.log(clean); // [1, 3, 5]
 
// For arrays without nesting, filter() also works
const cleaned = sparse.filter(() => true);
console.log(cleaned); // [1, 3, 5]

Flattening too deeply:

javascriptjavascript
// Data where nesting carries meaning
const orgChart = [
  "CEO",
  ["VP Engineering", ["Senior Dev", "Junior Dev"]],
  ["VP Marketing", ["Designer"]],
];
 
// flat(Infinity) destroys the hierarchy
const destroyed = orgChart.flat(Infinity);
console.log(destroyed);
// ["CEO", "VP Engineering", "Senior Dev", "Junior Dev", "VP Marketing", "Designer"]
// The organizational structure is lost

Best Practices

  1. Use flat() for one-level nesting by default. Most real-world data has one level of nested arrays (API responses, grouped data).
  2. Specify an explicit depth when you know the structure. flat(2) is clearer than flat(Infinity) when the data is always two levels deep.
  3. Prefer flatMap() for map-then-flatten patterns. It is more efficient (single pass) and more readable.
  4. Use flat() to clean sparse arrays. Calling flat() on a non-nested sparse array removes empty holes.
  5. Do not flatten meaningful hierarchies. If nesting represents a tree, parent-child relationship, or organizational structure, flattening destroys information.
Rune AI

Rune AI

Key Insights

  • Non-mutating: flat() returns a new array; the original stays unchanged
  • Default depth is 1: flattens one level of nesting; pass a number or Infinity for deeper
  • Removes sparse holes: flat() cleans empty slots from arrays as a side effect
  • flatMap() for map + flatten: prefer flatMap() when you need to transform and flatten in one step
  • Do not over-flatten: use a specific depth when nesting structure carries meaning
RunePowered by Rune AI

Frequently Asked Questions

Does flat() modify the original array?

No. flat() always returns a new array. The original array remains unchanged. If you need the result, assign it to a variable or chain it with other methods.

What does flat(Infinity) do?

It flattens all levels of nesting, no matter how deep. `[1, [2, [3, [4]]]]` becomes `[1, 2, 3, 4]`. Use it when you need a completely flat array regardless of how deeply nested the input is.

Can flat() remove undefined values?

flat() removes empty slots (holes) in sparse arrays, but it does not remove elements that are explicitly set to `undefined`. To remove undefined values, use [filter()](/tutorials/programming-languages/javascript/javascript-array-filter-method-complete-tutorial): `arr.filter(x => x !== undefined)`.

What is the difference between flat() and flatMap()?

flat() only flattens nested arrays by a specified depth. flatMap() first applies a mapping function to each element, then flattens the result by one level. flatMap() is equivalent to `arr.map(fn).flat()` but more efficient because it does both operations in a single pass.

Is flat() supported in all browsers?

flat() is an ES2019 feature supported in all modern browsers (Chrome 69+, Firefox 62+, Safari 12+, Edge 79+) and Node.js 11+. For environments that lack support, use `arr.reduce((acc, val) => acc.concat(val), [])` as a polyfill.

Conclusion

The flat() method replaces verbose flattening patterns with a single, readable call. For one-level nesting (the most common case), call flat() with no arguments. For deeper structures, pass a specific depth or use Infinity for complete flattening. When the operation is "transform each element and then flatten," use flatMap() instead. The key rules are to always assign the result (since flat() does not mutate), to use explicit depth values when the structure is known, and to avoid flattening hierarchies where nesting carries meaning.