lodash vs ramda vs remeda vs underscore
Functional Data Manipulation in JavaScript
lodashramdaremedaunderscoreSimilar Packages:

Functional Data Manipulation in JavaScript

lodash, ramda, remeda, and underscore are utility libraries that provide helper functions for common programming tasks like array manipulation, object handling, and function composition. lodash is the industry standard with a massive API surface. ramda focuses on functional programming with automatic currying and immutable data. remeda is a modern alternative designed for TypeScript and tree-shaking. underscore is the original library that inspired lodash, now mostly used for legacy support.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
lodash061,2351.41 MB1442 months agoMIT
ramda024,0751.2 MB1478 months agoMIT
remeda05,3752.84 MB142 days agoMIT
underscore027,335908 kB533 months agoMIT

Functional Utility Libraries: Lodash vs Ramda vs Remeda vs Underscore

When building JavaScript applications, you often need to transform data, filter lists, or manage object properties. The lodash, ramda, remeda, and underscore libraries provide tested utilities for these tasks, but they differ in style, type safety, and bundle impact. Let's compare how they handle common engineering challenges.

🧩 Coding Style: Object-First vs Data-Last

lodash and underscore use an object-first approach.

  • You pass the data as the first argument.
  • This feels natural for imperative code but can be harder to compose.
// lodash: Data is the first argument
import _ from 'lodash';
const result = _.map([1, 2, 3], (n) => n * 2);

// underscore: Similar object-first style
import _ from 'underscore';
const result = _.map([1, 2, 3], (n) => n * 2);

ramda and remeda use a data-last approach.

  • You pass the data as the last argument.
  • This makes it easier to chain functions together without nesting.
// ramda: Data is the last argument (curried)
import { map } from 'ramda';
const double = map((n) => n * 2);
const result = double([1, 2, 3]);

// remeda: Data is the last argument (functional)
import { map } from 'remeda';
const result = map([1, 2, 3], (n) => n * 2);

πŸ›‘οΈ TypeScript Support and Inference

Type safety is critical in modern frontend development. The libraries differ in how well they support TypeScript inference.

lodash has type definitions, but they can be loose.

  • You often need to cast types manually.
  • Chain types can get complex.
// lodash: Types may require casting
import _ from 'lodash';
const users = [{ id: 1 }];
// TypeScript might infer 'any' without extra care
const ids = _.map(users, (u) => u.id); 

ramda has strong types but can be verbose.

  • Functional types are precise but hard to read in errors.
  • Currying adds complexity to type signatures.
// ramda: Strong but complex types
import { map } from 'ramda';
// Type inference works but error messages can be long
const double = map((n: number) => n * 2);

remeda is built for TypeScript first.

  • Types are designed to infer cleanly in pipes.
  • Error messages are usually clearer.
// remeda: Clean type inference
import { map, pipe } from 'remeda';
// Types flow naturally through the pipe
const result = pipe(
  [1, 2, 3],
  map((n) => n * 2)
);

underscore has older type definitions.

  • Not optimized for modern TypeScript features.
  • May require @types/underscore which are less maintained.
// underscore: Legacy types
import _ from 'underscore';
// Basic types, less inference help
const result = _.map([1, 2, 3], (n) => n * 2);

πŸ“¦ Bundle Size and Tree Shaking

Bundle size affects load times. How you import these libraries matters.

lodash is large if imported fully.

  • You must import methods individually to save space.
  • Example: import map from 'lodash/map'.
// lodash: Modular import required for small bundles
import map from 'lodash/map';
// Without this, you might bundle the whole library

ramda is hard to tree-shake.

  • Functions are curried and interconnected.
  • Bundlers often include more code than needed.
// ramda: Named imports but tree-shaking is limited
import { map, filter } from 'ramda';
// Bundlers may struggle to remove unused parts

remeda is designed for tree-shaking.

  • Functions are independent and side-effect free.
  • Unused code is easily removed by bundlers.
// remeda: Optimized for tree-shaking
import { map, filter } from 'remeda';
// Unused functions are reliably dropped from the bundle

underscore is a single monolithic file.

  • Hard to split into smaller parts.
  • You pay for the whole library even if you use one function.
// underscore: Monolithic import
import _ from 'underscore';
// Entire library is included in the bundle

πŸ“… Maintenance and Future Proofing

Choosing a library means trusting its maintainers.

lodash is stable and widely used.

  • Updates are infrequent because it is feature-complete.
  • Safe for long-term projects.

ramda is stable with a dedicated community.

  • Focuses on functional correctness.
  • Changes are careful to avoid breaking composition.

remeda is actively developed.

  • Adds new features regularly.
  • Responds quickly to TypeScript updates.

underscore is in maintenance mode.

  • Not recommended for new projects.
  • Best suited for legacy systems that cannot migrate.

πŸ“Š Summary: Key Differences

Featurelodashramdaremedaunderscore
Style🧱 Object-firstπŸ§ͺ Functional (Curried)πŸ§ͺ Functional (Data-last)🧱 Object-first
TypeScript⚠️ Good but looseβœ… Strong but complexβœ… Excellent inference⚠️ Legacy types
Tree Shaking⚠️ Manual modular imports❌ Hard to shakeβœ… Built for shaking❌ Monolithic
Status🟒 Stable Standard🟒 Stable FP🟒 Active Modern🟑 Legacy / Maintenance

πŸ’‘ The Big Picture

lodash is the safe choice πŸ›‘οΈ for teams that want a vast API and don't want to debate style. It works everywhere and is well understood.

ramda is the functional choice πŸ§ͺ for teams committed to immutability and composition. It requires a shift in thinking but offers powerful tools.

remeda is the modern choice πŸš€ for TypeScript projects. It gives you functional benefits without the bundle bloat or type headaches.

underscore is the legacy choice πŸ•°οΈ. Avoid it for new work unless you are tied to an older stack.

Final Thought: For most new frontend projects, remeda offers the best balance of modern features and performance. If you need maximum compatibility and a huge API, lodash remains the king. Choose based on your team's comfort with functional style and your bundle constraints.

How to Choose: lodash vs ramda vs remeda vs underscore

  • lodash:

    Choose lodash if you need a comprehensive set of utilities that work consistently across different environments. It is ideal for large teams where standardization is key and bundle size is less of a concern due to its modular import options.

  • ramda:

    Choose ramda if your team embraces functional programming principles and wants automatic currying for function composition. It is suitable for projects that prioritize immutable data flows and point-free style coding.

  • remeda:

    Choose remeda if you are building a TypeScript-heavy application and care about bundle size. It offers the functional style of ramda but with better tree-shaking support and simpler type inference.

  • underscore:

    Choose underscore only if you are maintaining an older codebase that already depends on it. For new projects, it is better to evaluate modern alternatives due to slower update cycles and lack of modern features.

README for lodash

lodash v4.18.1

The Lodash library exported as Node.js modules.

Installation

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.

Support

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.