flatMap() combines map() and a single-level flat() into one efficient pass. It is the idiomatic tool whenever a mapping callback itself produces an array per element β like splitting each item into several results, or filtering by returning an empty array.
1Array.prototype.flatMap() | JavaScript Tutorial - In-Depth Guide Part 1
flatMap() maps each element to a new value, then flattens the result by exactly one level β equivalent to '.map(fn).flat(1)', but in a single pass.
[1, 2, 3].flatMap((n) => [n, n * 2]);
// [1, 2, 2, 4, 3, 6]Map, Then Flatten
2Array.prototype.flatMap() | JavaScript Tutorial - In-Depth Guide Part 2
flatMap() only flattens one level, regardless of how deep the returned arrays are nested β it does not accept a depth argument like flat() does.
[1].flatMap((n) => [[n]]); // [[1]] β only one level unwrappedAlways Exactly One Level
3Array.prototype.flatMap() | JavaScript Tutorial - In-Depth Guide Part 3
Returning an empty array from the callback effectively filters out that element β flatMap() can express map-and-filter in a single pass.
const evenSquares = numbers.flatMap((n) =>
n % 2 === 0 ? [n * n] : []
);Filter via Empty Arrays
4Array.prototype.flatMap() | JavaScript Tutorial - In-Depth Guide Part 4
flatMap() is the natural tool for 'splitting' each element into multiple results, like breaking sentences into words.
const words = sentences.flatMap((s) => s.split(' '));Splitting into Many
5Array.prototype.flatMap() | JavaScript Tutorial - In-Depth Guide Part 5
A regular map() followed by a manual flat() works too, but flatMap() communicates 'this mapping naturally produces a variable number of outputs per input' more directly.
// Equivalent, but flatMap is more direct:
const a = arr.map(fn).flat();
const b = arr.flatMap(fn);flatMap() vs map().flat()
6Step-by-Step Breakdown
flatMap() maps each element to a new value, then flattens the result by exactly one level β equivalent to '.map(fn).flat(1)', but in a single pass.
flatMap() only flattens one level, regardless of how deep the returned arrays are nested β it does not accept a depth argument like flat() does.
Checkpoint: Does flatMap() accept a depth argument to flatten more than one level, like flat() does?
- βYes, flatMap(fn, depth) is valid
- βNo, it always flattens exactly one level
Returning an empty array from the callback effectively filters out that element β flatMap() can express map-and-filter in a single pass.
Checkpoint: If a flatMap() callback returns an empty array for some elements, what happens to those elements in the final result?
- βThey contribute nothing, effectively filtering them out
- βThey appear in the result as undefined
flatMap() is the natural tool for 'splitting' each element into multiple results, like breaking sentences into words.
A regular map() followed by a manual flat() works too, but flatMap() communicates 'this mapping naturally produces a variable number of outputs per input' more directly.
Next, we'll explore 'Sorting with sort()'.
Level Up π
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Use flatMap() to Build a Flat, Accessible List from Grouped Source Data
When rendering a single accessible <ul> from data organized as groups, flatMap() can expand each group into its flat list of <li> elements in one step while still allowing a group-label item to be inserted per group if needed.
SEO Implications
- 1
No Direct SEO Effect
flatMap() is a data-transformation utility; SEO relevance is limited to correctness of derived content lists.
Best Practices
Use flatMap() Instead of map().flat() for One-Level Expansions
It avoids the intermediate array allocation and directly communicates "each input can produce zero or more outputs," which is clearer than a two-step chain.
Use flatMap()'s Empty-Array Trick Sparingly and Document It
Returning [] to filter is a clever but slightly non-obvious idiom; a short comment or a well-named helper keeps it readable for teammates unfamiliar with the pattern.
Frequent Bugs
Expecting flatMap() to flatten multiple levels of nesting when the callback returns deeply nested arrays, since only one level is ever flattened.
If deeper flattening is needed, follow flatMap() with an additional .flat(depth) call, or restructure the callback to return only one level of nesting.
Using flatMap() purely as a map() replacement without needing its flattening behavior, when a plain map() would be clearer since the callback never returns arrays.
Reserve flatMap() specifically for cases where the callback genuinely returns an array per element; use plain map() when the transformation is one-to-one.
Real-World Examples
Expanding Recurring Calendar Events
A calendar app needed to expand a list of recurring event templates into individual concrete event instances for a given date range.
const allInstances = recurringEvents.flatMap((event) =>
generateOccurrences(event, dateRange)
);