mrkeyoor.com_
Sun 20 Sept 17:50 UTC
npmUtilsupdated 20 Sept 2026

ramda review

Our Node 22 sandbox installed Ramda 0.32.0 in 1 second with no package dependencies. Ramda is a functional utility collection for plain JavaScript arrays, objects, and functions. Most calls are automatically curried and place the value being transformed last, which lets map, filter, sort, lenses, and object updates compose through pipe or compose. Functions return new values instead of mutating their inputs. Version 0.32.0 improves decimal arguments to range, repairs package exports, and updates examples for head, last, type, and pipeWith.

Verdict

Ramda earns its space when a JavaScript team consistently uses currying and data-last composition. TypeScript projects and browser entries should compare Remeda or es-toolkit first because Ramda lacks bundled types and our full import measured 15.7 KB gzipped.

We installed it

Lab card: what happened when we installed ramdaScreenshot of ramda documentation
Install✓ · 1s2 packages on disk · 4 MB
ImportESM import works · require() works · CommonJS package with exports map
Browser15.7 KBgzipped (56.9 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does ramda install cleanly?

Yes. In a fresh container with an empty cache, npm install ramda finished in 1 seconds, leaving 2 packages and 4 MB on disk. npm audit reported no known vulnerabilities.

How much does ramda add to a browser bundle?

15.7 KB gzipped (56.9 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does ramda work with both ESM and CommonJS?

Yes. Both import 'ramda' and require('ramda') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does ramda include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

ramda or remeda: which should you use?

remeda: Choose it for data-first and data-last pipelines designed around TypeScript inference. Ramda earns its space when a JavaScript team consistently uses currying and data-last composition.

When should you not use ramda?

The project is TypeScript-first. Ramda 0.32.0 ships no declarations; @types/ramda is maintained separately and complex currying or long pipe chains can exceed its inference.

API stability3/5Core functions such as map, filter, reduce, curry, pipe, compose, lenses, assocPath, equals, and groupBy have stayed familiar for years. The project still publishes 0.x versions, so minor releases carry no major-version compatibility promise, and the README warns against using a CDN `latest` URL. Version 0.32.0 lists no breaking API change, though it does alter decimal range behavior and fixes export-map resolution.
Docs4/5ramdajs.com provides a versioned page for each function with parameters, return types, category links, source links, and runnable examples. The README explains currying, data-last order, import forms, partial builds, browser globals, and bundler caveats. Guidance is weaker for TypeScript because types live in another package, and the README's Deno and CDN examples still show older Ramda versions rather than 0.32.0.
Maintenance3/5GitHub reports a push on 2026-07-26, 24056 stars, and 146 open issues and pull requests. The repository is neither archived nor disabled. Version 0.32.0 shipped on 2025-10-10 with a narrow range fix, package export repair, and documentation changes. Work continues, though releases are infrequent and the open tracker is substantial for a mature utility library.
Ecosystem4/5npm recorded 13949045 downloads for the week ending 2026-08-23. Ramda has community TypeScript declarations, a cookbook, direct source and ES subpath imports, browser distributions, and enough adoption that its data-last conventions are widely recognizable. The package has no runtime dependencies, while newer TypeScript-centered alternatives now compete on inference, smaller imports, and APIs closer to native JavaScript.

Use it if

  • The team deliberately writes data-last pipelines and wants currying built into ordinary collection and object helpers.
  • Nested plain objects need immutable reads and updates through lensPath, view, set, or over without introducing a custom collection type.
  • Transformation functions should be partially applied once and reused across several lists or records.
  • Code needs structural equality, grouping, indexing, or declarative field evolution beyond the native array methods used elsewhere in the project.
Skip it if

Setup reality

We installed Ramda 0.32.0 in a fresh Node 22 container in 1 second. Two packages occupied 4 MB afterward. Ramda declares zero direct dependencies and zero peer dependencies; its own unpacked package is 3452 KB and uses the MIT license. npm audit found zero known vulnerabilities. The package uses CommonJS as its base format and supplies an exports map; both require and ESM import worked in our sandbox.

There are no credentials, plugins, native builds, peer setup, or runtime config. Ramda has had no default export since versions after 0.25. Use import * as R from 'ramda', named imports, or const R = require('ramda'). The exports map also exposes ramda/es/, ramda/src/, and ramda/dist/*. Version 0.32.0 includes a package export fix, so older workarounds around subpath resolution deserve retesting before they are kept.

TypeScript is a separate decision. We found no bundled declarations, and the README directs users to @types/ramda. Curried overloads, the placeholder R.__, and long pipe chains are difficult for community declarations to represent precisely. JavaScript users avoid that mismatch. TypeScript teams should compile representative pipelines before choosing Ramda, rather than assuming the simplest map example predicts inference across the application.

Our esbuild test imported the full package namespace and produced 56.9 KB minified, 15.7 KB gzipped. The package marks itself side-effect free, yet the README says destructured imports do not always guarantee a partial bundle and documents direct ramda/src imports plus bundler-specific tree shaking. Measure the production entry. Currying also allocates wrapper functions, so a tight numeric or collection loop should be benchmarked against a native loop or array method.

Patterns

Build a reusable list pipeline compose-pipeline

import {filter, map, pipe, prop} from 'ramda'

const activeNames = pipe(
  filter(user => user.active),
  map(prop('name')),
)

const names = activeNames(users)

pipe runs left to right. The first function may accept several arguments; later functions receive the previous result.

Reuse a partially applied filter partially-apply

import {filter, propEq} from 'ramda'

const onlyActive = filter(propEq(true, 'active'))
const customers = onlyActive(allCustomers)
const staff = onlyActive(allStaff)

Ramda's data argument comes last, so leaving it out creates a function waiting for the collection.

Read a nested value with a fallback read-default-path

import {pathOr} from 'ramda'

const currency = pathOr('USD', ['billing', 'currency'], account)

pathOr returns the fallback when the resolved value is null or undefined. Other false values such as 0 or an empty string are preserved.

Change a nested field immutably update-nested-path

import {assocPath} from 'ramda'

const updated = assocPath(['profile', 'timezone'], 'UTC', user)
console.log(user.profile.timezone)
console.log(updated.profile.timezone)

assocPath copies the containers along the changed path and reuses untouched references. It does not deep-clone the whole object.

Read and update through one lens use-lens

import {lensPath, over, set, view} from 'ramda'

const totalLens = lensPath(['invoice', 'total'])
const total = view(totalLens, order)
const corrected = set(totalLens, 25, order)
const taxed = over(totalLens, value => value * 1.2, order)

view reads, set replaces, and over transforms. All three use the same path definition; set and over return new outer objects.

Transform selected object fields evolve-record

import {evolve, toLower, trim} from 'ramda'

const normalized = evolve({
  email: value => toLower(trim(value)),
  attempts: value => value + 1,
}, record)

Fields absent from the transformation object pass through. A transformation for a property missing from the input is not called.

Group rows by a computed key group-records

import {groupBy, prop} from 'ramda'

const byStatus = groupBy(prop('status'), tickets)
const openTickets = byStatus.open ?? []

groupBy returns an object of arrays. Property keys are strings, so choose a Map-based approach when key identity or non-string keys matter.

Index records by identifier index-records

import {indexBy, prop} from 'ramda'

const usersById = indexBy(prop('id'), users)
const owner = usersById['42']

Later records replace earlier ones that produce the same key. Object keys are coerced to strings.

Apply ordered sort rules sort-multiple-fields

import {ascend, descend, prop, sortWith} from 'ramda'

const ranked = sortWith([
  descend(prop('score')),
  ascend(prop('name')),
], entries)

sortWith returns a sorted copy and leaves the input array untouched. Earlier comparators take precedence over later tie breakers.

Compute one result from several branches combine-derived-values

import {converge, divide, length, sum} from 'ramda'

const average = converge(divide, [sum, length])
const mean = average([4, 8, 12])

Each branch receives the same original arguments. Empty input makes this example divide zero by zero and return NaN, so guard that case in production code.

Adapt arguments before a call transform-with-arguments

import {multiply, useWith} from 'ramda'

const areaFromStrings = useWith(multiply, [Number, Number])
const area = areaFromStrings('6', '7')

useWith applies one transformer per supplied position. Extra arguments beyond the transformer list pass through unchanged.

Compare nested values structurally compare-structures

import {equals} from 'ramda'

const unchanged = equals(
  {tags: ['a', 'b'], when: new Date('2026-01-01')},
  {tags: ['a', 'b'], when: new Date('2026-01-01')},
)

equals handles many built-in value types and cyclic structures. Its semantics differ from JSON string comparison and strict reference equality.

Alternatives

PackageRegistryPick it when
remedanpmChoose it for data-first and data-last pipelines designed around TypeScript inference.
es-toolkitnpmChoose it for typed, tree-shakeable utility functions when automatic currying is not part of the coding style.
rambdanpmChoose it for a smaller Ramda-like API with built-in TypeScript types, after checking which functions differ or are missing.
lodashnpmChoose it for a broad data-first utility set that fits imperative JavaScript and has extensive existing usage material.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.