lodash and underscore are comprehensive utility libraries that provide hundreds of helper functions for working with arrays, objects, strings, and more. They are designed to be general-purpose toolkits for everyday JavaScript tasks. In contrast, natural-orderby and sort-by are specialized packages focused specifically on sorting logic. natural-orderby handles alphanumeric sorting in a way that matches human intuition, while sort-by offers a lightweight, declarative way to order arrays of objects by specific keys. Together, these tools represent the spectrum from all-in-one utility belts to focused, single-responsibility modules.
When building frontend applications, developers often face the choice between importing a massive utility library or installing small, focused packages for specific tasks. lodash and underscore represent the all-in-one approach, offering vast collections of helper functions. On the other hand, natural-orderby and sort-by solve specific problems related to ordering data. Understanding the trade-offs between these options helps you keep your codebase clean and your bundle size reasonable.
The primary difference lies in what each package aims to solve. lodash and underscore are designed to be swiss army knives. They handle everything from deep cloning objects to throttling functions and sorting arrays. This convenience comes with a larger footprint, though modern bundlers can tree-shake unused code.
In contrast, natural-orderby and sort-by do one thing well. They do not provide methods for mapping, filtering, or object manipulation. They exist solely to make sorting easier or more accurate. If your project only needs better sorting logic, adding a 70kb utility library is overkill.
All four packages offer ways to sort arrays, but their APIs and capabilities differ. Below is how you would sort a list of users by age using each library.
lodash provides a robust sortBy method that handles null values and iteratees gracefully.
import _ from 'lodash';
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 35 }
];
const sorted = _.sortBy(users, 'age');
// Result: [{ name: 'Bob', age: 25 }, ...]
underscore offers a nearly identical API for basic sorting, reflecting its historical influence on lodash.
import _ from 'underscore';
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 35 }
];
const sorted = _.sortBy(users, 'age');
// Result: [{ name: 'Bob', age: 25 }, ...]
sort-by is designed for minimalism. It exports a function that you pass directly to the native array sort method.
import sortBy from 'sort-by';
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 35 }
];
// Mutates the original array
users.sort(sortBy('age'));
// Result: [{ name: 'Bob', age: 25 }, ...]
natural-orderby focuses on value comparison rather than just key extraction. It is often used in conjunction with standard sort methods for complex values.
import { naturalOrderBy } from 'natural-orderby';
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 35 }
];
// Returns a comparator function
const sorted = users.sort(naturalOrderBy(user => user.age));
// Result: [{ name: 'Bob', age: 25 }, ...]
Standard sorting treats numbers as characters. This means "item 10" comes before "item 2" because "1" is less than "2". This is often wrong for user interfaces. natural-orderby solves this specific problem, while the others require extra work.
lodash does not support natural sorting out of the box. You must write a custom comparator.
import _ from 'lodash';
const files = ['file10.txt', 'file2.txt', 'file1.txt'];
// Requires custom logic or Intl.Collator
const sorted = files.sort((a, b) =>
a.localeCompare(b, undefined, { numeric: true })
);
// Result: ['file1.txt', 'file2.txt', 'file10.txt']
underscore also lacks built-in natural sorting. You rely on native JavaScript features similarly.
import _ from 'underscore';
const files = ['file10.txt', 'file2.txt', 'file1.txt'];
// Custom comparator required
const sorted = _.sortBy(files, file => file);
// Note: _.sortBy alone does not handle numeric strings naturally
sort-by is strictly for key-based sorting and does not handle natural ordering of string values internally.
import sortBy from 'sort-by';
const files = ['file10.txt', 'file2.txt', 'file1.txt'];
// Will sort alphabetically by default
files.sort(sortBy());
// Result: ['file1.txt', 'file10.txt', 'file2.txt'] (Incorrect for humans)
natural-orderby excels here. It is built specifically to handle mixed alphanumeric strings correctly without extra configuration.
import { naturalOrderBy } from 'natural-orderby';
const files = ['file10.txt', 'file2.txt', 'file1.txt'];
const sorted = files.sort(naturalOrderBy());
// Result: ['file1.txt', 'file2.txt', 'file10.txt'] (Correct)
The JavaScript language has evolved significantly. Native methods like Array.prototype.sort and Intl.Collator now cover many use cases that previously required libraries.
lodash remains actively maintained and is safe for production. It adapts to new environments and fixes security issues promptly. It is a stable dependency for large teams.
underscore receives updates less frequently. While stable, it is often considered a legacy choice. Many of its features overlap with native JavaScript or lodash. New projects rarely start with underscore today.
natural-orderby is a focused tool. As long as your sorting needs involve human-readable strings, it remains relevant. Native localeCompare is an alternative, but this package simplifies the API.
sort-by is very small and stable. However, for simple key sorting, native code is often just as clear. It is useful when you need to sort by nested keys without writing accessor functions.
| Feature | lodash | underscore | natural-orderby | sort-by |
|---|---|---|---|---|
| Primary Goal | General Utilities | General Utilities | Natural Sorting | Key-Based Sorting |
| Bundle Size | Large (Modular) | Medium | Tiny | Tiny |
| Natural Sort | β (Custom logic) | β (Custom logic) | β (Built-in) | β (Alphabetic) |
| Maintenance | β Active | β οΈ Slow | β Stable | β Stable |
| Best For | Complex Apps | Legacy Code | File Lists | Simple Object Lists |
For most modern frontend applications, start with native JavaScript features. If you need robust utility functions across a large codebase, lodash is the safest and most powerful choice. Use its modular imports to avoid bloating your bundle.
Avoid underscore for new projects unless you have a specific reason to match an existing backend or legacy system. It does not offer significant advantages over lodash or native JS today.
If your main pain point is sorting file names, versions, or IDs that contain numbers, natural-orderby is a perfect fit. It saves you from writing complex comparators. For simple lists of objects where you just need to order by a property, sort-by is convenient, but native sorting with a simple accessor function is often sufficient.
Choose the tool that matches the complexity of your problem β do not import a kitchen sink when you only need a spoon.
Choose lodash if you need a reliable, feature-complete utility library with modular imports to keep bundle size in check. It is the industry standard for teams that want consistent behavior across environments and extensive documentation.
Choose natural-orderby when you need to sort lists containing mixed numbers and text, such as file names or version strings, where standard sorting fails. It is the right tool for human-readable ordering.
Choose sort-by if you want a tiny dependency just for sorting arrays of objects by keys without pulling in a massive utility library. It is ideal for simple data grids or lists where performance and size matter.
Choose underscore if you are maintaining a legacy codebase that already depends on it or if you prefer its specific functional programming style. For new projects, consider modern alternatives due to slower update cycles.
The Lodash library exported as Node.js modules.
Using npm:
$ npm i -g npm
$ npm i --save lodash
In Node.js:
// Load the full build.
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load the FP build for immutable auto-curried iteratee-first data-last methods.
var fp = require('lodash/fp');
// Load method categories.
var array = require('lodash/array');
var object = require('lodash/fp/object');
// Cherry-pick methods for smaller browserify/rollup/webpack bundles.
var at = require('lodash/at');
var curryN = require('lodash/fp/curryN');
See the package source for more details.
Note:
Install n_ for Lodash use in the Node.js < 6 REPL.
Tested in Chrome 74-75, Firefox 66-67, IE 11, Edge 18, Safari 11-12, & Node.js 8-12.
Automated browser & CI test runs are available.