
Lodash _.groupBy() is a JavaScript utility function that takes a collection (array or object) and groups its elements into an object where the keys are determined by a given criterion and the values are arrays of elements that match that key. It returns a plain object — not a Map or array.
// Quick syntax
_.groupBy(collection, iteratee)
Here is a quick example:
const users = [
{ name: "Alice", department: "Engineering" },
{ name: "Bob", department: "Marketing" },
{ name: "Charlie", department: "Engineering" },
{ name: "Diana", department: "Marketing" }
];
const grouped = _.groupBy(users, 'department');
// Result:
// {
// Engineering: [{ name: "Alice", ... }, { name: "Charlie", ... }],
// Marketing: [{ name: "Bob", ... }, { name: "Diana", ... }]
// }
Each element is placed into the group that matches its department value. The original array is not modified.
In this guide, you will learn how to use _.groupBy() to group arrays and objects by property, multiple keys, custom functions, nested values, and computed values. You will also learn how to combine _.groupBy() with other Lodash methods for aggregation and how to achieve the same result with native JavaScript.
🔍 Also check out our guides on Lodash Merge and Lodash SortBy for more data manipulation techniques.
- How to Install and Import Lodash groupBy
- Lodash groupBy Syntax and Parameters
- GroupBy a Simple Array
- Lodash groupBy Array of Objects
- GroupBy with a Custom Function
- Lodash groupBy Multiple Keys
- GroupBy Nested Object Properties
- Combining groupBy with Other Lodash Methods
- Handling Edge Cases
- Lodash groupBy vs Native JavaScript
- Practical Real-World Examples
- Performance Considerations
- Related Lodash Guides
- FAQs
- What is Lodash groupBy and how does it work?
- Can I group by multiple keys with Lodash groupBy?
- Does Lodash groupBy handle undefined or null values?
- What is the difference between Lodash groupBy and partition?
- Is there a native JavaScript alternative to Lodash groupBy?
- Does Lodash groupBy mutate the original array?
How to Install and Import Lodash groupBy
Install the full library:
npm install lodash
Import _.groupBy() in your code:
// ES6 — import only groupBy (tree-shakable)
import groupBy from 'lodash/groupBy';
// CommonJS
const groupBy = require('lodash/groupBy');
// Or import the full library
import _ from 'lodash';
// then use _.groupBy()
Lightweight alternative — install only the groupBy module:
npm install lodash.groupby
import groupBy from 'lodash.groupby';
Tip: The full Lodash library is ~70KB (minified + gzipped). Importing
lodash/groupByor installinglodash.groupbykeeps your bundle lean at ~2KB.
If you are using Lodash in the browser:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
const result = _.groupBy([6.1, 4.2, 6.3], Math.floor);
// { '4': [4.2], '6': [6.1, 6.3] }
</script>
Lodash groupBy Syntax and Parameters
Here is the complete syntax:
_.groupBy(collection, [iteratee=_.identity])
| Parameter | Type | Description |
|---|---|---|
collection | Array or Object | The collection to group. |
[iteratee] | Function or String | The criterion for grouping. Can be a property name (string) or a function that returns the group key. |
| Returns | Object | An object where keys are group names and values are arrays of grouped elements. |
Important behaviors:
- The order of grouped values is determined by the order they appear in the original collection
- The iteratee is called with one argument:
(value) - If a property value is
undefined, it creates a key called"undefined" _.groupBy()does not mutate the original collection
GroupBy a Simple Array
The simplest use case — grouping values using a function:
// Group numbers by their floor value
const grouped = _.groupBy([6.1, 4.2, 6.3], Math.floor);
console.log(grouped);
// Output: { '4': [4.2], '6': [6.1, 6.3] }
// Group strings by their first letter
const words = ["apple", "avocado", "banana", "blueberry", "cherry"];
const grouped = _.groupBy(words, (word) => word[0]);
console.log(grouped);
// Output:
// {
// a: ["apple", "avocado"],
// b: ["banana", "blueberry"],
// c: ["cherry"]
// }
// Group numbers by even/odd
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
const grouped = _.groupBy(numbers, (n) => n % 2 === 0 ? 'even' : 'odd');
console.log(grouped);
// Output: { odd: [1, 3, 5, 7], even: [2, 4, 6, 8] }
Lodash groupBy Array of Objects
This is the most common use case. Pass a property name as a string to group objects by that property:
const employees = [
{ name: "Alice", department: "Engineering", salary: 95000 },
{ name: "Bob", department: "Marketing", salary: 75000 },
{ name: "Charlie", department: "Engineering", salary: 105000 },
{ name: "Diana", department: "Marketing", salary: 80000 },
{ name: "Eve", department: "Design", salary: 85000 }
];
const byDepartment = _.groupBy(employees, 'department');
console.log(byDepartment);
// Output:
// {
// Engineering: [
// { name: "Alice", department: "Engineering", salary: 95000 },
// { name: "Charlie", department: "Engineering", salary: 105000 }
// ],
// Marketing: [
// { name: "Bob", department: "Marketing", salary: 75000 },
// { name: "Diana", department: "Marketing", salary: 80000 }
// ],
// Design: [
// { name: "Eve", department: "Design", salary: 85000 }
// ]
// }
Each employee object is placed intact into its department group. You can then work with each group independently.
Accessing Grouped Results
// Get all engineers
const engineers = byDepartment['Engineering'];
// [{ name: "Alice", ... }, { name: "Charlie", ... }]
// Count per department
const counts = _.mapValues(byDepartment, (group) => group.length);
// { Engineering: 2, Marketing: 2, Design: 1 }
// Get all department names
const departments = Object.keys(byDepartment);
// ["Engineering", "Marketing", "Design"]
GroupBy with a Custom Function
For more complex grouping logic, pass a function instead of a property name:
const products = [
{ name: "Budget Phone", price: 199 },
{ name: "Mid-Range Laptop", price: 799 },
{ name: "Premium Tablet", price: 1299 },
{ name: "Budget Earbuds", price: 49 },
{ name: "Mid-Range Monitor", price: 449 }
];
const byPriceRange = _.groupBy(products, (product) => {
if (product.price < 100) return 'budget';
if (product.price < 500) return 'mid-range';
if (product.price < 1000) return 'premium';
return 'luxury';
});
console.log(byPriceRange);
// Output:
// {
// budget: [{ name: "Budget Earbuds", price: 49 }],
// "mid-range": [{ name: "Budget Phone", price: 199 }, { name: "Mid-Range Monitor", price: 449 }],
// premium: [{ name: "Mid-Range Laptop", price: 799 }],
// luxury: [{ name: "Premium Tablet", price: 1299 }]
// }
Group by Date Parts
const orders = [
{ id: 1, date: "2025-01-15", total: 99 },
{ id: 2, date: "2025-01-20", total: 149 },
{ id: 3, date: "2025-02-05", total: 79 },
{ id: 4, date: "2025-02-18", total: 199 },
{ id: 5, date: "2025-03-01", total: 59 }
];
// Group by month
const byMonth = _.groupBy(orders, (order) => order.date.substring(0, 7));
console.log(byMonth);
// Output:
// {
// "2025-01": [{ id: 1, ... }, { id: 2, ... }],
// "2025-02": [{ id: 3, ... }, { id: 4, ... }],
// "2025-03": [{ id: 5, ... }]
// }
Group by Boolean Condition
const tasks = [
{ title: "Write docs", completed: true },
{ title: "Fix bug", completed: false },
{ title: "Deploy", completed: true },
{ title: "Code review", completed: false }
];
const grouped = _.groupBy(tasks, 'completed');
console.log(grouped);
// Output:
// {
// true: [{ title: "Write docs", ... }, { title: "Deploy", ... }],
// false: [{ title: "Fix bug", ... }, { title: "Code review", ... }]
// }
// Count completed vs pending
console.log(`Done: ${grouped['true'].length}, Pending: ${grouped['false'].length}`);
// Output: "Done: 2, Pending: 2"
Lodash groupBy Multiple Keys
_.groupBy() natively supports only one key. To group by multiple keys, you have several approaches:
Approach 1: Composite Key String
Concatenate multiple properties into a single key:
const sales = [
{ product: "Widget", region: "North", amount: 100 },
{ product: "Widget", region: "South", amount: 200 },
{ product: "Gadget", region: "North", amount: 150 },
{ product: "Widget", region: "North", amount: 300 },
{ product: "Gadget", region: "South", amount: 250 }
];
const grouped = _.groupBy(sales, (item) => `${item.product}_${item.region}`);
console.log(grouped);
// Output:
// {
// "Widget_North": [{ product: "Widget", region: "North", amount: 100 }, { ... amount: 300 }],
// "Widget_South": [{ product: "Widget", region: "South", amount: 200 }],
// "Gadget_North": [{ product: "Gadget", region: "North", amount: 150 }],
// "Gadget_South": [{ product: "Gadget", region: "South", amount: 250 }]
// }
Approach 2: Nested GroupBy
Group by the first key, then group each group by the second key:
const byProductThenRegion = _.mapValues(
_.groupBy(sales, 'product'),
(productGroup) => _.groupBy(productGroup, 'region')
);
console.log(byProductThenRegion);
// Output:
// {
// Widget: {
// North: [{ product: "Widget", region: "North", amount: 100 }, { ... amount: 300 }],
// South: [{ product: "Widget", region: "South", amount: 200 }]
// },
// Gadget: {
// North: [{ product: "Gadget", region: "North", amount: 150 }],
// South: [{ product: "Gadget", region: "South", amount: 250 }]
// }
// }
Approach 3: JSON Key
For more than two keys, serialize as JSON:
const grouped = _.groupBy(sales, (item) =>
JSON.stringify({ product: item.product, region: item.region })
);
// Access a specific group:
const widgetNorth = grouped[JSON.stringify({ product: "Widget", region: "North" })];
GroupBy Nested Object Properties
To group by a nested property, use a function to access the nested value:
const employees = [
{ name: "Alice", address: { city: "Kolkata", state: "WB" } },
{ name: "Bob", address: { city: "Mumbai", state: "MH" } },
{ name: "Charlie", address: { city: "Pune", state: "MH" } },
{ name: "Diana", address: { city: "Howrah", state: "WB" } }
];
const byState = _.groupBy(employees, (emp) => emp.address.state);
console.log(byState);
// Output:
// {
// WB: [{ name: "Alice", ... }, { name: "Diana", ... }],
// MH: [{ name: "Bob", ... }, { name: "Charlie", ... }]
// }
Note: Unlike
_.sortBy(), you cannot use dot notation strings like'address.state'with_.groupBy(). You must use a function.
Combining groupBy with Other Lodash Methods
The real power of _.groupBy() comes from combining it with other Lodash utilities:
GroupBy + sumBy (Aggregate Totals)
const expenses = [
{ category: "Food", amount: 50 },
{ category: "Transport", amount: 30 },
{ category: "Food", amount: 65 },
{ category: "Entertainment", amount: 100 },
{ category: "Transport", amount: 45 }
];
const grouped = _.groupBy(expenses, 'category');
const totals = _.mapValues(grouped, (items) => _.sumBy(items, 'amount'));
console.log(totals);
// Output: { Food: 115, Transport: 75, Entertainment: 100 }
GroupBy + map (Transform Groups)
const orders = [
{ customer: "Alice", item: "Laptop", price: 999 },
{ customer: "Alice", item: "Mouse", price: 29 },
{ customer: "Bob", item: "Keyboard", price: 79 }
];
const grouped = _.groupBy(orders, 'customer');
const summary = _.mapValues(grouped, (orders) => ({
orderCount: orders.length,
totalSpent: _.sumBy(orders, 'price'),
items: orders.map(o => o.item)
}));
console.log(summary);
// Output:
// {
// Alice: { orderCount: 2, totalSpent: 1028, items: ["Laptop", "Mouse"] },
// Bob: { orderCount: 1, totalSpent: 79, items: ["Keyboard"] }
// }
GroupBy + maxBy (Find Best in Each Group)
const students = [
{ name: "Alice", subject: "Math", score: 95 },
{ name: "Bob", subject: "Math", score: 88 },
{ name: "Charlie", subject: "Science", score: 92 },
{ name: "Diana", subject: "Science", score: 97 }
];
const grouped = _.groupBy(students, 'subject');
const topStudents = _.mapValues(grouped, (group) => _.maxBy(group, 'score').name);
console.log(topStudents);
// Output: { Math: "Alice", Science: "Diana" }
GroupBy + sortBy (Sort Within Groups)
Need to sort items within each group? Combine _.groupBy() with _.sortBy():
const products = [
{ name: "Widget C", category: "Tools", price: 30 },
{ name: "Widget A", category: "Tools", price: 10 },
{ name: "Gadget B", category: "Electronics", price: 50 },
{ name: "Gadget A", category: "Electronics", price: 20 }
];
const grouped = _.groupBy(products, 'category');
const sortedGroups = _.mapValues(grouped, (items) => _.sortBy(items, 'price'));
// Each category's products are now sorted by price
Handling Edge Cases
Undefined and Null Values
When a property value is undefined or null, _.groupBy() converts it to a string key:
const items = [
{ name: "A", category: "Food" },
{ name: "B", category: undefined },
{ name: "C", category: null },
{ name: "D", category: "Food" }
];
const grouped = _.groupBy(items, 'category');
console.log(grouped);
// Output:
// {
// Food: [{ name: "A", ... }, { name: "D", ... }],
// undefined: [{ name: "B", ... }],
// null: [{ name: "C", ... }]
// }
To handle this gracefully, provide a default in the iteratee:
const grouped = _.groupBy(items, (item) => item.category || 'Uncategorized');
// Now undefined and null items go into "Uncategorized"
Empty Arrays
const grouped = _.groupBy([], 'category');
console.log(grouped);
// Output: {}
_.groupBy() returns an empty object for empty collections — no errors.
Lodash groupBy vs Native JavaScript
Using Object.groupBy() (ES2024)
JavaScript now has a native Object.groupBy() method (Stage 4, available in Node 21+ and modern browsers):
// Native (ES2024)
const grouped = Object.groupBy(users, (user) => user.department);
// Lodash
const grouped = _.groupBy(users, 'department');
Using Array.reduce()
For environments without Lodash or Object.groupBy():
// Native reduce
const grouped = users.reduce((acc, user) => {
const key = user.department;
if (!acc[key]) acc[key] = [];
acc[key].push(user);
return acc;
}, {});
// Lodash — same result, cleaner syntax
const grouped = _.groupBy(users, 'department');
Comparison Table
| Feature | _.groupBy() | Object.groupBy() | Array.reduce() |
|---|---|---|---|
| Syntax | _.groupBy(arr, 'key') | Object.groupBy(arr, fn) | Manual reduce logic |
| String shorthand | ✅ 'property' | ❌ Needs function | ❌ Needs function |
| Browser support | All (via npm) | ES2024+ / Node 21+ | All |
| Bundle size | ~2KB | 0KB (native) | 0KB (native) |
| Chaining with Lodash | ✅ Seamless | ❌ Manual | ❌ Manual |
When to use _.groupBy(): Your project uses Lodash, you need the string shorthand, or you need to support older browsers.
When to use native: You target modern browsers/Node, want zero dependencies, or the grouping logic is simple.
Practical Real-World Examples
E-Commerce: Group Products by Category
const products = [
{ id: 1, name: "Laptop", category: "Electronics", price: 999 },
{ id: 2, name: "T-Shirt", category: "Clothing", price: 29 },
{ id: 3, name: "Headphones", category: "Electronics", price: 199 },
{ id: 4, name: "Jeans", category: "Clothing", price: 59 },
{ id: 5, name: "Novel", category: "Books", price: 15 }
];
const catalog = _.groupBy(products, 'category');
// Render a category sidebar:
Object.entries(catalog).forEach(([category, items]) => {
console.log(`${category} (${items.length} products)`);
});
// Electronics (2 products)
// Clothing (2 products)
// Books (1 products)
Analytics: Group Events by Date
const pageViews = [
{ url: "/home", timestamp: "2025-02-01T10:00:00Z" },
{ url: "/about", timestamp: "2025-02-01T14:30:00Z" },
{ url: "/home", timestamp: "2025-02-02T09:15:00Z" },
{ url: "/contact", timestamp: "2025-02-02T16:45:00Z" }
];
const byDate = _.groupBy(pageViews, (view) => view.timestamp.split('T')[0]);
const dailyCount = _.mapValues(byDate, (views) => views.length);
console.log(dailyCount);
// { "2025-02-01": 2, "2025-02-02": 2 }
API Response Processing
const apiResponse = [
{ id: 1, status: "success", data: "..." },
{ id: 2, status: "error", message: "Not found" },
{ id: 3, status: "success", data: "..." },
{ id: 4, status: "error", message: "Timeout" }
];
const { success = [], error = [] } = _.groupBy(apiResponse, 'status');
console.log(`${success.length} succeeded, ${error.length} failed`);
// "2 succeeded, 2 failed"
// Handle errors
error.forEach(e => console.error(`Request ${e.id}: ${e.message}`));
Tip: If your API returns partial data across multiple requests, use
_.merge()to deep merge responses before grouping them.
Performance Considerations
_.groupBy() iterates through the collection once:
- Time complexity: O(n) — where n is the number of elements
- Space complexity: O(n) — creates a new object with all elements distributed into groups
Tips:
_.groupBy()is highly efficient for its purpose — a single pass O(n) operation- For very large datasets (1M+ items), consider processing in chunks or using a streaming approach
- The iteratee function should be lightweight — avoid expensive computations inside it
- If you need to group and then immediately transform, chain the operations to avoid multiple passes:
// ✅ Efficient — groups and transforms in two passes
const result = _.mapValues(_.groupBy(data, 'category'), (items) => items.length);
// ❌ Inefficient — groups, then iterates groups, then iterates each group
const grouped = _.groupBy(data, 'category');
const result = {};
for (const key in grouped) {
result[key] = 0;
for (const item of grouped[key]) {
result[key]++;
}
}
Related Lodash Guides
- Lodash _.merge() — Deep Merge Objects & Arrays — Learn how to deep merge nested objects without losing inner properties, customize merge behavior with
_.mergeWith(), and avoid prototype pollution. - Lodash _.sortBy() — Sort Objects, Arrays & Descending Order — Learn how to sort arrays of objects by property, multiple fields, descending order with
_.orderBy(), and case-insensitive sorting.
FAQs
What is Lodash groupBy and how does it work?
_.groupBy() is a Lodash function that takes a collection (array or object) and a criterion (property name or function), then returns an object where keys are group names and values are arrays of elements matching that key. It iterates through the collection once, placing each element into the appropriate group based on the iteratee's return value.
Can I group by multiple keys with Lodash groupBy?
_.groupBy() natively supports only one key. For multiple keys, you can create a composite key string (_.groupBy(arr, (x) => x.key1 + '_' + x.key2)), use nested groupBy calls (_.mapValues(_.groupBy(arr, 'key1'), (g) => _.groupBy(g, 'key2'))), or serialize keys as JSON.
Does Lodash groupBy handle undefined or null values?
Yes. When a grouping key is undefined or null, _.groupBy() creates string keys "undefined" or "null" respectively. To handle these gracefully, use a function with a default: _.groupBy(arr, (x) => x.category || 'Uncategorized').
What is the difference between Lodash groupBy and partition?
_.groupBy() splits a collection into multiple groups based on any criterion. _.partition() splits a collection into exactly two groups — items that match a predicate and items that don't. Use _.partition() when you only need a true/false split.
Is there a native JavaScript alternative to Lodash groupBy?
Yes. Object.groupBy() was introduced in ES2024 and is available in Node 21+ and modern browsers. For older environments, Array.prototype.reduce() can achieve the same result. However, _.groupBy() offers cleaner syntax with string property shorthands and integrates seamlessly with other Lodash utilities.
Does Lodash groupBy mutate the original array?
No. _.groupBy() returns a new object containing references to the original elements. The original collection is never modified. However, the elements inside each group are the same references — not deep copies — so modifying an element in a group will also modify it in the original array.
Ready to Implement This in Production?
Skip the months of development and debugging. Our team will implement this solution with enterprise-grade quality, security, and performance.