mrkeyoor.com_
Thu 10 Sept 07:01 UTC
Dev Toolsevaluationupdated 10 Sept 2026

lo review

Lo is a Go utility library that applies familiar operations such as map, filter, group, and reduce to typed slices and maps. It cuts repetitive loops from application code and also includes separate packages for lazy iteration, in-place changes, and parallel callbacks.

Verdict

Our Lo run installed 16 packages in 9 seconds, built in 28 seconds, and passed all 12 go test checks in 26 seconds. Use its stable v1 core when repeated collection loops are obscuring ordinary application code, but keep direct loops in measured hot paths. Treat parallel, mutable, and experimental SIMD as separate decisions because each changes the cost or behavior of the simple helper model.

We ran it

Lab card: what happened when we ran loScreenshot of lo (lo.samber.dev)
Install✓ · 9s16 packages
Build✓ · 28s
Tests✓ · 26s12 passed · 0 failed of 12 (go test)
Repo673 files~52,718 lines of source · 8.2 MB · 7 CI workflows

Answers from our run

Does lo build from source?

Dependencies installed in 9 seconds (16 packages), and the build succeeded in 28 seconds. We cloned commit a94fb4b into a clean Debian container with 3 CPUs and no project-specific setup.

Do lo's tests pass?

Yes: 12 of 12 passed when we ran the project's own test command (go test). Some failures need services or credentials a bare container does not have.

Who should not use lo?

Teams with a standard-library-only dependency policy: the README says 5 to 10 helpers overlap Go's slices and maps packages.

What are the alternatives to lo?

Go slices and maps, go-funk, Mo. Our Lo run installed 16 packages in 9 seconds, built in 28 seconds, and passed all 12 go test checks in 26 seconds.

Setup5/59-second install and no failed build or test step
Docs3/5Broad reference, but getting-started examples conflict with source
Community5/521,428 stars with a Sep 9 push and current issue work
Maturity4/5Stable v1 core; SIMD and some helper semantics remain unsettled

Who it’s for

Go teams repeating the same slice and map transformations across an application.
Developers who want generic helpers without reflection or runtime services.
Go 1.23 or newer projects that can use the lazy it package.
Teams that need callbacks which can return errors and stop a transform early.

Who it’s NOT for

Teams with a standard-library-only dependency policy: the README says 5 to 10 helpers overlap Go's slices and maps packages.
Performance-sensitive code where a direct loop is acceptable: Lo's own benchmark concludes that the loop wins on CPU and memory.
Large collections whose callbacks need bounded concurrency: the current parallel implementation starts one goroutine per element and exposes no worker limit.
Developers who expect website examples to compile unchanged: the getting-started page describes a worker-pool argument and a pointer-based mutable call that do not match the current source signatures.
Projects requiring a stable SIMD API or older Go toolchain: the SIMD package is experimental, may break, and current work targets Go 1.27.

Setup reality

Our sandbox installed 16 packages in 9 seconds. The build succeeded in 28 seconds, then go test passed all 12 checks in 26 seconds with 0 failures. The checkout contained 673 files, about 52,718 source lines, and used 8.2 MB before installation.

Core Lo requires Go 1.18 and no credentials, services, or runtime configuration. The README says release code has no dependencies outside the standard library. Lazy iterators require Go 1.23 or newer, while current experimental SIMD work targets Go 1.27.

Package choice matters more than installation. The main API returns new values, mutable changes backing arrays, and parallel starts a goroutine for each input. The website's getting-started examples have drifted from those current signatures, so use the README, source, and Go package docs together.

Go 1.18 gets typed collection helpers without a runtime service

Lo packages familiar collection operations as generic Go functions. Map, Filter, Reduce, grouping, lookup, set-style operations, string conversion, retries, and channel helpers sit behind ordinary imports. The core module targets Go 1.18 and requires no server, account, or configuration file. Its README also states that release code has no dependency outside the Go standard library. That makes adoption easier to reverse than a utility package with a deep module graph.

The library has several personalities. Core functions generally return a value, it works lazily with Go 1.23 sequences, mutable writes into a slice's backing array, and parallel runs callbacks in goroutines. Version 1.53.0 added error-returning transform variants such as MapErr and ReduceErr, which can stop when a callback fails. The README also links an optional Claude Code skill from a separate repository; normal Lo use does not depend on it.

The standard library overlaps 5 to 10 Lo helpers

Go's own slices and maps packages now cover part of Lo's original ground. The README acknowledges an overlap of 5 to 10 helpers and argues that the rest of the API still earns its place. That is the right adoption question. A single slices.Contains call does not justify a new dependency, while a service full of grouping, chunking, deduplication, and error-aware transforms may become easier to read with one consistent vocabulary.

Generics keep the usual operations typed and avoid the reflection model used by older libraries. They do not make a chain of callbacks automatically clearer than a loop. Index arguments, allocations, early exits, and error flow are visible faster in plain Go when the transformation is unusual. Lo works best on ordinary, easily named operations. Keep the loop when it expresses the business rule better or when a profiler says the helper call sits on a hot path.

What happened when we ran it

Our sandbox installed 16 packages in 9 seconds at commit a94fb4b. The build completed successfully in 28 seconds, and go test finished in 26 seconds with 12 passed and 0 failed out of 12. Those results came from an unprivileged golang:1.24-bookworm container with 3 CPUs, 8 GB of RAM, and no secrets. Lo needed no external service during those repository checks.

The checkout had 673 files, roughly 52,718 lines of source, and an 8.2 MB disk footprint before installation. We found 7 CI workflow files, no Dockerfile, and no tests directory. Test files live alongside Go packages, which is normal for Go and explains the absent top-level directory. The clean build and test result is useful evidence for repository health; it is not a benchmark of one helper against a handwritten loop.

Parallel Map starts one goroutine for every input item

The parallel.Map implementation allocates its result at input length, adds that length to a wait group, and starts one goroutine for every element. Each goroutine writes to its own result index, so output order follows input order. There is no concurrency limit in the function signature. That can be convenient for a modest set of slow callbacks, but a very large collection or a downstream service with strict limits needs a worker pool owned by the calling application.

The current website introduction describes built-in worker pools and shows a lop.Map call with a worker count of 4. Current source accepts only the collection and callback. This is more than cosmetic drift because the example implies a resource control the implementation does not provide. Issue 702 remains open to lint Markdown code blocks. Until the docs are checked against source signatures, copy package examples into a compiler before using them as design evidence.

Mutable Filter only shortens the slice it returns

mutable.Filter rewrites the existing backing array and returns a shorter slice header. The caller's original slice variable keeps its old length if the return value is ignored, leaving old tail positions visible and often duplicating the last kept value. Current source comments explain that behavior directly. Open issue 842 demonstrates the surprise with a 3-item slice whose ignored return leaves the retained final item visible twice. Assign the result every time, or use the non-mutating core helper.

Text and set helpers deserve similar contract tests. Issue 948 asks whether SnakeCase should place _ before digits. Issue 974 shows Capitalize uppercasing format characters after percent signs, and issue 303 disputes repeated output when Intersect sees duplicates in one collection. These reports may end in documentation, code changes, or a later major version. For code that serializes identifiers or depends on multiset behavior, pin v1 and test the exact cases your application sends.

A September 9 push offsets the older v1.53.0 release date

GitHub recorded a September 9, 2026 push, 21,428 stars, and 220 combined issues and pull requests. A separate issue-only search returned 124 open issues. The latest tagged release, v1.53.0, was published on March 2, while issue and pull request activity continued into September. That combination describes active maintenance with a crowded queue; the 220 figure should not be read as a count of defects.

Experimental SIMD is the clearest stability boundary. The v1.53.0 notes call its API unstable, and issue 803 now discusses a Go 1.27 implementation with breaking changes during development. The v2 discussion explicitly says there is no immediate requirement for a major release, so it is a specification thread rather than a delivery promise. For most teams, the sensible choice is the stable core package, backed by our 12 passing checks, with parallel and mutable imports reviewed like separate libraries.

Alternatives

ProjectWhat it isPick it when
Go slices and maps gh↗The standard library includes generic helpers for common slice and map work.pick this instead when the required operations already exist in `slices` or `maps` and avoiding another public API matters.
go-funkA reflection-based collection utility library that predates Go generics.pick this instead when an older Go codebase cannot adopt generic APIs and reflection is acceptable.
MoGeneric Option, Result, Either, Future, and task types from the same author.pick this instead when explicit absence and error containers matter more than collection helpers.

What people are saying

  1. [velocity-scout] samber/lo

Sources

  1. Lo repository and README
  2. Lo v1.53.0 release
  3. Lo getting-started guide
  4. Parallel slice implementation
  5. Mutable slice implementation
  6. Issue 702: lint Markdown code blocks
  7. Issue 842: Mutable Filter return-value surprise
  8. Issue 948: SnakeCase digit behavior

More dev tools reviews

d2 · PEASS-ng · typst · imgui · gofr · CleanArchitecture · the whole board →