# Remeda and the quiet work of narrowing return types

> A TypeScript utility library whose three most recent releases contain no new functions at all, only a compile-time string check revised twice in five days, sitting inside a monorepo that has started committing agent instruction files.

**remeda/remeda** — A utility library for JavaScript and TypeScript.

- Repository: https://github.com/remeda/remeda
- Website: http://remedajs.com
- Stars: 5,442 · Forks: 173
- Language: TypeScript
- License: MIT
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/remeda-remeda

## Two different descriptions of the same project

The README opens with a claim about precedence: Remeda is the first data-first and data-last utility library designed especially for TypeScript. Both halves of that matter. Data-first means the array leads, as in `filter(array, fn)`. Data-last means the function leads and the array is supplied later, as in `filter(fn)(array)`. Carrying both in one library is unusual enough that the claim is at least checking the box honestly.

The repository description, the short blurb that appears in search results and dependency listings, says something much smaller: a utility library for JavaScript and TypeScript. Both statements come from the same project at the same time. One claims a first; the other claims nothing and quietly covers both languages. Neither is false. They are different registers for different audiences, and reading them together tells you something useful: the library positions itself against TypeScript-first competitors while its package metadata stays broadly compatible.

Installation, meanwhile, is spelled out across five package managers in the same README.

```bash
npm install remeda
pnpm add remeda
yarn add remeda
```

The supporting numbers are substantial. 5,429 stars and 174 forks place Remeda firmly in the category of libraries that get depended on rather than merely evaluated. The topic tags are unpretentious: functional, programming, typescript, utility. The last recorded push to the default branch came on 2026-09-18, and the repository is not archived.

## What data-first, data-last, and lazy evaluation actually buy

The two calling styles are not stylistic variants. They suit different shapes of problem, and the README lists both as separate capabilities rather than one being sugar over the other.

```javascript
import { pipe, forEach, unique, take } from "remeda";
```

Lazy evaluation is the third feature and the one that ties them together. The library documents lazy support through `pipe` and a curried variant called `piped`, so a chain can be assembled without intermediate arrays being materialized until something forces them.

The example the README gives is small but reveals the intended usage: an array with duplicates goes through a logging step, then deduplication, then a limit, and the result is three values. The `pipe` chain is the spine, and each function is a single-purpose step that reads as a line.

```javascript
  unique(),
  take(3),
```

Two properties in the feature list are worth more attention than they get. The first is that runtime and types are both tested extensively with full code coverage, which is a claim about testing the type layer itself rather than only the emitted JavaScript. The second is tree-shakability alongside support for both CommonJS and ESM, which means the package is expected to be safe to import piecemeal from either module system.

Documentation is described as JSDoc, which is the mechanism that makes in-editor function documentation possible. For a library whose entire value is type precision, that is the piece that makes the types legible at the call site rather than only on a website.

## Three releases, no new functions

The three most recent releases are the clearest signal about where this library spends its effort. Not one of them adds a function.

Version 2.48.0, published on 2026-09-09, fixes `startsWith` and `endsWith` so that a disjoint literal prefix or suffix is rejected at compile time. Both issue 1434 and issue 1432 are closed by it.

Version 2.49.0, published on 2026-09-14, touches the same two functions and closes the same two issues again. Its description differs in one important word: reject disjoint prefix or suffix *instead of disabling the return type*.

Version 2.50.0, published later the same day on 2026-09-14, fixes `isNot` to resolve trivial fixed-value conditions, closing issue 1440.

That middle entry is the interesting one. A fix shipped on the ninth to reject a literal prefix at compile time, and five days later a fix shipped to change what that rejection does to the inferred return type, while referencing the same pair of issues. Both descriptions are accurate descriptions of what each release did. Read together they show a project that treated a compile-time error as acceptable on Tuesday and as an unacceptable type regression by the following week. That is not sloppy release discipline; it is a type-level bug found after the fact.

The pattern across all three is worth stating plainly. The work is about what the compiler infers, not about what the code does at runtime. `isNot` resolving trivial fixed-value conditions is a type-narrowing repair. Two `startsWith` and `endsWith` entries in a row are type-narrowing repairs. A library that advertises itself as designed especially for TypeScript is shipping the thing it claims to be designed around.

## A monorepo whose root version is not the library version

The root manifest describes a private workspace, not the published package.

```json
"version": "2.0.0",
"type": "module",
"private": true,
```

So the number you see at the repository root is 2.0.0, while the releases the project publishes are at 2.50.0 and climbing. Both facts are in the repository at the same time. The root manifest is private and its version field tracks the container, not the library inside it, so nothing is broken; but anyone reading `package.json` at the root to answer "what version is this" gets an answer that is fifty minor versions behind.

The workspaces are the other thing worth naming.

```json
"workspaces": [
  "packages/remeda",
  "packages/docs",
  "packages/stackblitz-template",
  "packages/brand"
```

Four of them, and only one is the library. There is a documentation site, a StackBlitz template, and a brand package, which matches the README's link to a hosted docs site and the light and dark lockup images at the top of the README. The build script at the root simply builds across workspaces, which is why a library change and a docs rebuild are hard to separate in practice.

Dependency management is pinned unusually tightly. The overrides block exists to pin Vite to a specific range for Vitest and the tooling that depends on it, alongside a similar pin for another package's own Vite.

```json
"vitest": {
  "vite": "~7.3.1"
},
```

The block also pins an override for an unrelated transitive dependency. Nobody writes overrides like that for fun; they write them after an install breaks in a way that is hard to reproduce from a single lockfile entry.

## Sixteen open issues, and why that number is suspicious in a good way

Remeda carries 5,429 stars and 16 open issues. That ratio is unusual. Libraries at this scale usually accumulate a visible backlog of stale issues, and many carry hundreds.

Sixteen suggests aggressive triage rather than an empty queue. It is consistent with the release pattern: issues get closed by a shipped fix rather than by a label, as with 1434 and 1432 closing together in 2.48.0 and then 1440 closing in 2.50.0. It also fits the presence of a contributing guide, a code of conduct, and a security policy in the tree, which together describe a project that expects outside contributions to go through a process.

The README badge block goes further than most. Beyond the usual license, language, and coverage badges, Remeda links an OpenSSF Scorecard badge, an OpenSSF Best Practices badge, and a Libraries.io SourceRank badge. Those are supply chain signals, not code quality signals. A utility library that many projects depend on indirectly has reason to care about how its own dependencies and build steps look from outside.

Migration guidance is treated as a first-class concern too, with dedicated guides for Lodash and Ramda, the two libraries a TypeScript team is most likely to be replacing. For a project whose selling point is dropping into an existing codebase, a documented path away from the incumbent matters as much as the API surface.

Installation is offered across five package managers, ending with a JSR-scoped add for Deno rather than another npm-shaped command.

```bash
deno add jsr:@remeda/remeda
```

The scoped JSR name and the unscoped npm name are two different package identifiers, which is worth noting for anyone pinning both.

## The tree that documents how the work gets done

The file list is where this repository stops being a library and becomes a workplace. Alongside the expected `.github/`, `LICENSE`, and `README.md`, the tree contains a `.husky/` directory, `lint-staged.config.ts`, and a root script that installs Husky on prepare.

```json
"prepare": "husky"
```

Git hooks wired to Husky, combined with lint-staged and Prettier configured through its own config file, describes a project where the commit itself is a checkpoint rather than a transport step. Prettier plugins for shell scripts and package manifests are in the dev dependencies, which explains why both a `prettier-plugin-sh` and `prettier-plugin-pkg` sit there.

Then there are the files that have no functional reason to be in a utility library's repository: `AGENTS.md`, `CLAUDE.md`, a `.agents/` directory, a `.claude/` directory, and a `skills-lock.json`. Those names are the configuration surface used to hand repository context to automated coding assistants, and committing them means the guidance travels with a clone rather than living in one maintainer's account.

Two other entries suggest how people are expected to work here. A `remeda.code-workspace` points editors at the right folders in a monorepo without manual setup, and a `.nvmrc` pins the Node version, which removes an entire class of "works on my machine" report before it happens.

The contrast with the release history is the interesting part. The published artifact is a small, precise, thoroughly typed library. The repository that produces it contains agent instructions, pinned runtimes, shell formatting, and hook infrastructure. The surface a consumer installs and the surface a contributor works in have drifted far apart, and only the first one is constrained by the library's promise.

## Conclusion

Remeda's recent history explains what the library actually is better than its README does. Three consecutive releases shipped predicate correctness and type precision, one of them correcting a five-day-old approach to the same check, which is the signature of a project whose remaining work is precision rather than surface area. The two call styles it advertises are real and distinct rather than an alias for each other, and the tiny open issue count against 5,429 stars suggests the maintenance burden is triage, not firefighting. The uncomfortable details sit in the repository metadata: a first-ism claim that the repository description quietly contradicts, a root manifest versioned 2.0.0 for a library shipping 2.50.0, and a growing set of committed agent configuration files that say more about how work gets done there than any of the docs do.

## FAQ

### What is Remeda?

Remeda is a MIT licensed utility library for JavaScript and TypeScript, published to npm and described by its authors as the first data-first and data-last utility library designed especially for TypeScript. It supports both filter(array, fn) and filter(fn)(array) calling styles, offers lazy evaluation through pipe, is tree-shakable, and ships both CommonJS and ESM builds.

### What is the difference between Remeda and Lodash?

The primary difference is typing and calling convention. Remeda is built for TypeScript with types written to be as specific as possible, and it adds data-last currying and lazy pipe chains that Lodash does not provide. Remeda also ships a documented migration guide for Lodash on remedajs.com, plus a separate guide for Ramda, since those are the two libraries a TypeScript team is most likely replacing.

### How do you install Remeda?

The README lists five commands: npm install remeda, pnpm add remeda, yarn add remeda, bun install remeda, and for Deno the JSR scoped add jsr:@remeda/remeda. Note that the JSR package uses the scoped name @remeda/remeda while the npm package is simply remeda, so they are two different identifiers.

### How active is Remeda and how large is its backlog?

Very active on releases and unusually light on backlog. The repository shows 5,429 stars, 174 forks, and only 16 open issues, with the default branch last pushed on 2026-09-18. Recent releases are dense: v2.48.0 on 2026-09-09, then v2.49.0 and v2.50.0 both on 2026-09-14.

### What kinds of changes ship in Remeda releases?

Mostly type-level and predicate-correctness work rather than new functions. The last three releases contain none: v2.48.0 made startsWith and endsWith reject disjoint literal prefixes at compile time, v2.49.0 revised that rejection so it no longer disables the return type, and v2.50.0 fixed isNot so it resolves trivial fixed-value conditions.

## Sources

- [License: MIT](https://github.com/remeda/remeda/blob/main/LICENSE)
- [Project website](http://remedajs.com)
- [README](https://github.com/remeda/remeda/blob/main/README.md)
- [Releases](https://github.com/remeda/remeda/releases)
- [remeda/remeda on GitHub](https://github.com/remeda/remeda)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/remeda-remeda
