Beginner’s Guide to the JavaScript reduce() Function

Jacinto Wong
Jacinto Wong
hero image

Arrays are great for storing data, but what if you need something more? A total, a summary, or a new shape entirely?

Well that's where reduce() comes in.

In this guide I’ll break down what this function is, how it works, give examples of how you can use it, as well cover common mistakes to avoid.

Sidenote: If you want to learn more about JavaScript, be sure to check out Andrei’s Complete Web Developer course, as well as my Beginner and Advanced JavaScript projects:

learn javascript

We have everything you need to become a full-stack JavaScript developer in 2025.

Graduates from these programs are now working at Google, Tesla, Amazon, Apple, IBM, Uber, Facebook, Shopify + other top tech companies. There’s no reason why you couldn’t do the same!

With that out of the way, let’s get into this 5-minute tutorial.

What is reduce() and how does it work?

When you’re writing JavaScript, you’re usually working with groups of things, such as a list of names, numbers, or records from a form. These collections are stored in arrays, which is just another name for lists of items in a specific order - kind of like a shopping list.

For example

Here’s an array with 3 items.

const colors = ['blue', 'red', 'green'];

But the goal isn’t usually to just store a list like this. You probably want to do something with it right? Maybe add up the total of some numbers, count how many times something appears, or perhaps transform it into something else entirely.

And that’s exactly where reduce() comes in.

At its core, reduce() helps you take a list and turn it into a single result. That could be a number, a string, an object, or even another array. You get to decide what the final result looks like, and reduce() helps you build it, step by step.

Here’s the basic shape of how it works:

array.reduce((accumulator, currentValue) => {
  return updatedAccumulator
}, initialValue)

That might look confusing right now, but don’t worry. Once you see it in action, it starts to make more sense.

In plain terms:

  • It starts with an initial value (like 0, {}, or [])
  • Then it looks at the first item in the array
  • It updates the running total or result (called the “accumulator”)
  • Then it passes that new result to the next item
  • This repeats until the whole array has been processed

The key idea is that each step builds on the last, and when the loop ends, you’re left with the final result.

5 ways you can use reduce() to help with your code

Now that you’ve got the gist, let’s look at some real problems you can solve using reduce().

#1. How to use reduce() to sum numbers in a list

This is one of the simplest and most common uses for reduce(), which is taking a list of numbers and adding them up into a single number.

For example

Let’s say that you’ve got a shopping cart represented as an array of prices, and you want to know the total combined cost.

Here we can see all the item prices:

const prices = [12.99, 5.99, 23.50, 9.99]

So, you want to end up with:

42.48

Here’s how you’d do it with reduce():

const total = prices.reduce((sum, price) => {
  return sum + price
}, 0)

console.log(total) // 42.48

So let’s break this down:

  • We start with 0 as our initial value. That’s the starting value of sum
  • On the first loop, the price is 12.99. We add that to sum (which is currently at 0), and return 12.99
  • On the next loop, the next price is 5.99. Now sum is already 12.99, so we add the 5.99 and return 18.98
  • And so on, until we reach the final value: 42.48

Each time, reduce() returns the updated total, and passes it to the next step. No loop needed. No manual tracking. Just a clean way to move through the list and build your result.

#2. How to use reduce() to group items by property

This pattern is really common any time you want to organize a list into buckets based on some property.

For example

Let’s say you have a list of tasks, and each one has a status like “open” or “done.”

const tasks = [
  { name: 'Write draft', status: 'open' },
  { name: 'Fix typos', status: 'done' },
  { name: 'Add code sample', status: 'open' },
  { name: 'Publish', status: 'done' }
]

However, you want to group them based on their status so you can see how many are in progress or completed, so that it looks something like this:

{
  open: [
    { name: 'Write draft', status: 'open' },
    { name: 'Add code sample', status: 'open' }
  ],
  done: [
    { name: 'Fix typos', status: 'done' },
    { name: 'Publish', status: 'done' }
  ]
}

Here’s how you’d do it with reduce():

const grouped = tasks.reduce((acc, task) => {
  const key = task.status
  if (!acc[key]) {
    acc[key] = []
  }
  acc[key].push(task)
  return acc
}, {})

So let’s break this down:

  • We start with an empty object {} (acc)
  • For each task in the tasks array, we check its status, and use that as the key
  • If that key doesn’t exist in the accumulator yet, we create an empty array for it
  • Then we push the task into the right group, helping to filter the items into the correct open or done status

Handy right?

#3. How to use reduce() to flatten paginated results

Sometimes an API doesn’t give you all your data in one go. Instead, it returns pages like a list of products, messages, or search results, and each as its own array.

This means that before you can work with the full dataset, you’ll often need to combine those pages into one flat list. The good news is that’s where reduce() comes in.

For example

Let’s say you’re fetching user comments from three pages of an API, and each page returns an array:

const commentPages = [
  ['Nice post!', 'Thanks for sharing'],
  ['Great tips'],
  ['This helped a lot', 'Bookmarked']
]

Before rendering them in your UI, you want one clean list of all comments:

['Nice post!', 'Thanks for sharing', 'Great tips', 'This helped a lot', 'Bookmarked']

Here’s how you’d do that with reduce():

const flat = commentPages.reduce((acc, current) => {
  return acc.concat(current)
}, [])

So let’s break this down:

  • We start with an empty array as our initial result (acc)
  • For each page, we use .concat() to merge it into the growing list
  • By the end, you have one flat array with all the comments

This is super common when working with paginated APIs, file uploads (one batch at a time), or form data collected in steps. Instead of loops or .push(), reduce() gives you a cleaner, declarative way to merge everything together.

#4. How to use reduce() to combine values into a string

Let’s say a user fills out a form on your site and picks a few tags to describe their interests. You want to take that array of values and turn it into a readable sentence like:

“You’re subscribed to: marketing, analytics, growth.”

Basically just letting them know the 3 confirmed topics they’ve subscribed to.

Now, that sounds simple but real-world arrays often include empty strings, null values, or fields you want to ignore.

For example

const selected = ['marketing', '', 'analytics', null, 'growth']

If you just used .join(', '), you’d get awkward gaps like this:

"marketing, , analytics, , growth"

But reduce() gives you the control to clean it up and format it exactly how you want.

Here’s how:

const sentence = selected.reduce((acc, word) => {
  if (word && word.trim()) {
    return acc.length > 0 ? acc + ', ' + word : word
  }
  return acc
}, '')

const final = `You're subscribed to: ${sentence}.`

Let’s unpack what’s happening here:

  • We start with an empty string as the initial value (acc)

  • Each time through the loop, we check if the word is valid:

    • It must not be null, undefined, or, using trim() determine that it’s not an empty/whitespace-only string
  • If it is valid:

    • We check if anything is already in the sentence
      • If so, we add a comma and a space before appending the word
      • If not, we just use the word (no comma for the first one)
  • If it’s invalid, we skip it entirely

  • At the end, we’ve built a clean, readable list with proper punctuation

  • Then we wrap the result in a full sentence like:

"You're subscribed to: marketing, analytics, growth."

This approach works anywhere you need full control over how strings are built from arrays:

  • Formatting a summary from user input
  • Constructing a CSV row while skipping invalid data
  • Assembling a Markdown or HTML string from raw content
  • Conditionally adding labels, tags, or links

Once you’ve seen how to shape a string this way, .join() starts to feel a bit limiting.

#5. How to use reduce() to combine values across objects

This pattern comes in handy any time you’re dealing with repeated data across multiple objects and need to combine it into a single summary. Perhaps daily sales logs, API responses from different regions, or even vote counts from different polls.

For example

Imagine you run an online grocery service with multiple warehouses. Each warehouse tracks how many units of each fruit were sold that day:

const reports = [
  { apples: 3, oranges: 5 },
  { apples: 2, bananas: 4 },
  { oranges: 1, bananas: 2 }
]

Your dashboard needs to show the total units sold per fruit, across all warehouses. (Obviously they would sell higher numbers than this, but just so you get the idea).

So you want to transform that into:

{ apples: 5, oranges: 6, bananas: 6 }

Here’s how you’d do that with reduce():

const totals = reports.reduce((acc, report) => {
  for (let fruit in report) {
    acc[fruit] = (acc[fruit] || 0) + report[fruit]
  }
  return acc
}, {})

So let’s break this down:

  • We start with an empty object {} as the accumulator (acc)
  • For each report, we loop through its keys (like apples, oranges)
  • If the key already exists in the accumulator, we add to it
  • If it doesn’t, we initialize it at 0 and then add the value

This approach scales no matter how many reports you have or which fruits appear. It’s dynamic, flexible, and avoids hardcoding anything.

You’ll often use this trick any time you’re merging totals, building summaries, or syncing data from multiple sources.

Pretty cool, eh?

So now you can see how it works, let's look at some common issues when using this function.

Common mistakes when using reduce()

These are the most common mistakes that I see developers making.

Mistake #1. Using reduce() when you don’t need it

This happens a lot, because once people learn how powerful reduce() is they start using it everywhere, even when it’s not the best choice.

But reduce() is meant for one thing: taking a list and turning it into a single result. That result might be a number, an object, a string, or a new structure entirely. But if you’re not actually doing that, you probably don’t need to use it.

For example

  • If you’re just changing each value in a list, such as doubling some prices or uppercasing some names, then map() will do the job with less code and more clarity
  • Or if you’re picking out certain values, such as keeping only completed tasks then filter() is a better fit

You’ll know you’re misusing reduce if you find yourself adding a lot of conditions inside the callback, or doing extra work just to make it behave like a different method. If the code feels more confusing than it should, that’s usually your sign 😉.

reduce() is brilliant when you actually need to reduce something. But when you're just transforming or selecting values, it's okay to reach for something simpler.

Mistake #2. Forgetting to set an initial value

This one sneaks up on a lot of people, but when you use reduce(), you have the option to pass in an initial value. Usually something like 0, {}, or [], depending on what kind of result you’re building.

And while JavaScript technically lets you skip it, that can lead to subtle bugs and confusing behavior.

Here’s what happens:

If you don’t pass an initial value, reduce() will automatically use the first item in the array as the starting value, and then begin the loop with the second item.

That means:

  • You have one less loop iteration
  • Your callback function needs to assume the first item is already in the right format
  • And if the array is empty? reduce() just crashes with an error

Not great right?

Now compare that to explicitly setting an initial value:

  • It guarantees the loop always runs the same way
  • It makes the result type predictable (you always start with a number, an object, or whatever you need)
  • And it makes your code easier to reason about, especially when someone else is reading it later

So as a general rule, always pass an initial value. Even if it feels optional, it’ll save you weird bugs and make your code easier to trust.

Mistake #3. Returning the wrong thing (or forgetting to return anything at all)

This one can be frustrating because the code might look fine at first glance, but your result ends up being undefined, or just completely wrong.

So here’s what’s happening:

Every time your reduce() callback runs, it needs to return the updated version of the result you’re building. That return value becomes the input for the next step in the list.

However, if you forget to return something, or return the wrong thing, everything breaks.

Take this example:

const total = numbers.reduce((sum, num) => {
  sum += num
})

It looks okay, but the total will be undefined.

Why?

Because there's no return sum at the end of the function, and so without that, reduce() doesn't know what the next value of sum should be.

Even more confusing, you might still see partial results in the middle of the loop, which makes the bug harder to spot!

The solution is fairly simple, and it’s to always double-check that your callback returns the updated result at the end of each step.

So:

  • If you're using curly braces {}, you must include a return keyword
  • And if you're using an arrow function without braces, it returns automatically
// This works
const total = numbers.reduce((sum, num) => sum + num, 0)

Small detail, but it makes all the difference.

Mistake #4. Using complex logic that makes reduce hard to read

One of the things that makes reduce() powerful is that you can do almost anything inside that callback function. But that’s also what makes it dangerous.

It’s easy to cram a bunch of logic inside it such as if statements, calculations, nested conditions, until suddenly it becomes hard to tell what the code is even doing.

When that happens, it’s usually a sign that your function is trying to do too much.

For example

const grouped = data.reduce((acc, item) => {
  if (item.status === 'open') {
    if (!acc.open) acc.open = []
    acc.open.push(item)
  } else if (item.status === 'closed') {
    if (!acc.closed) acc.closed = []
    acc.closed.push(item)
  }
  return acc
}, {})

This code block works but it's not very easy to follow. You’ve got branching logic, repeated code, and a lot happening in one block.

In cases like this, it's usually better to move that logic into a separate function. That keeps your reduce clean, and makes the code easier to test, read, and fix later.

Just because you can do it inside reduce, doesn’t always mean you should!

Give reduce() a try in your own projects!

So as you can see, reduce is an incredibly handy function to use. However, the best way to fully learn anything is to give it a try for yourself, so go ahead and pick a real problem you’ve run into with an array, and see how you’d solve it using reduce.

Once you do, you’ll start to see just how often this one function can simplify the way you write code.

P.S.

Remember, if you want to learn more about JavaScript, be sure to check out Andrei’s Complete Web Developer course, as well as my Beginner and Advanced JavaScript projects:

learn javascript

We have everything you need to become a full-stack JavaScript developer in 2025, build a portfolio, and get hired.

In fact, graduates from these programs are now working at Google, Tesla, Amazon, Apple, IBM, Uber, Facebook, Shopify + other top tech companies. There’s no reason why you couldn’t do the same!

As a ZTM member, you get access to all these courses and more in a single membership.

Plus, once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students and other working tech professionals, as well as access to every other course in our library!


More from Zero To Mastery

How to Become a Full-Stack Web Developer & Get Hired in 2025 preview
How to Become a Full-Stack Web Developer & Get Hired in 2025
32 min read

Learn everything you need to know to become a Full-Stack Web Developer, as well as how to get hired as one in 2025 with this step-by-step guide!

CSS vs HTML: Comparison Guide (With Code Examples) preview
CSS vs HTML: Comparison Guide (With Code Examples)
24 min read

HTML vs CSS. Learn their differences, pros, and cons, and how to use them with different variables for dynamic site creation!

Beginners Guide To Flexbox With Bootstrap preview
Popular
Beginners Guide To Flexbox With Bootstrap
15 min read

Learn how to use Flexbox features for responsive design inside of Bootstrap. I've also included some code examples to show you how easy it is to start using!