# quiver: utility libraries for Dart iterables, async and time

> Quiver is Google's collection of small Dart utility libraries, split into independent pieces for iterables, async computation, caches, collections, pattern matching, strings and time, plus fake implementations for tests. The interesting one for application code is the Clock, which exists so that time dependent code can be tested, and the release history stops in May 2022 even though the repository is still being touched.

**google/quiver-dart** — A set of utility libraries for Dart

- Repository: https://github.com/google/quiver-dart
- Website: https://pub.dev/packages/quiver
- Stars: 1,063 · Forks: 133
- Language: Dart
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/google-quiver-dart

## A bag of small libraries rather than a framework

Quiver describes itself as a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality. The repository description is shorter still, a set of utility libraries for Dart.

What makes that worth a dependency is the way the package is cut. The README lists its main libraries individually, each with its own documentation link, and each covers one subject area: quiver.async for Futures, Streams and async computations, quiver.cache, quiver.check, quiver.collection, quiver.core, quiver.iterables, quiver.pattern, quiver.strings and quiver.time.

That structure has a practical consequence. You do not take the package as a whole, you import the one library that solves your problem, so the cost of adding the LruMap is the LruMap and not the whole set. The README is organised library by library for the same reason.

The licence is Apache 2.0, and the repository carries the files that usually accompany it, a LICENSE file, a NOTICE file, a PATENTS file and an AUTHORS file, which is the conventional set for a Google owned open source project.

The maintenance picture is the part to look at carefully. The repository is not archived, but the last push was on 2026-04-02, and the published versions are 3.1.0, 3.0.1+2 and 3.0.1+1, all published on 2022-05-03. So the last release of the package itself is from 2022, and the code has been touched since without a new version on pub.dev. For a dependency that many Dart projects carry, that is a question you should have an answer to before you add it.

## iterables and core: the itertools and Optional answers

Two libraries cover the ground a Dart developer reaches for most often.

quiver.iterables holds the combinators: concat, count, cycle, enumerate, merge, partition, range and zip create, transform or combine Iterables in different ways, similar to Python's itertools. There are also the accessors, with min, max and extent retrieving the minimum and maximum elements from an iterable.

Two of the types in that library are the reason to know it exists. GeneratingIterable is described as an easy way to create lazy iterables that produce elements by calling a function, with the common use case of traversing properties in an object graph, like the parent relationship in a tree. That is a lazily evaluated iterator over a structure you do not want to materialise. InfiniteIterable is a base class for Iterables that throws on operations that require a finite length, which is a guard rail rather than a convenience, since it turns an accidental infinite loop into an error at the point of the mistake.

quiver.core holds two things. Optional is a way to represent optional values without allowing null, and hashObjects, hash2, hash3 and hash4 generate high-quality hashCodes for a list of objects or for two, three or four arguments respectively.

The Optional deserves a note. Dart's own type system has null safety built in, so an Optional type in a utility library is a deliberate second opinion about how to model absence, and codebases that adopt it end up with two ways to say a value might not be there. That is a real integration cost, and it is the reason to check what your own analysis options say before you adopt the whole library rather than a single helper.

## async: StreamBuffer, StreamRouter and a self correcting Metronome

quiver.async is the largest of the libraries and the one with the most concrete utilities.

collect collects the completion events of an Iterable of Futures into a Stream, which is the bridge between the two async styles. enumerate and concat are the Stream versions of the same-named quiver.iterables methods, so the same vocabulary works on both sides.

StreamBuffer allows for the orderly reading of elements from a stream, such as a socket. FutureStream turns a Future of a Stream into a Stream which emits the same events as the stream returned from the future, which is what lets you await the connection and then treat it as a stream. StreamRouter splits a Stream into multiple streams based on a set of predicates, so one input feed can drive several consumers by content.

Then the timing helpers. CountdownTimer is a simple countdown timer that fires events in regular increments. Metronome is described as a self-correcting alternative to Timer.periodic, providing a simple, tracking periodic stream of DateTime events with optional anchor time. The difference from a plain periodic timer is that it does not accumulate drift, because it measures against a fixed anchor rather than adding an interval to the previous fire time. If you are polling something on a schedule and the schedule matters, that is the whole point of the class.

There is also stringFromByteStream, which constructs a string from a stream of byte lists, a small utility that exists because byte streams arrive in chunks and string decoding across chunk boundaries is a common source of bugs.

## cache: an asynchronous map with eviction policies

quiver.cache is the smallest library and the one with the clearest abstraction.

Cache is described as a semi-persistent, asynchronously accessed, mapping of keys to values. The distinction from a Map is stated in the same breath: caches are similar to Maps, except that the cache implementation might store values in a remote system, so all operations are asynchronous, and caches might have eviction policies.

Both of those words carry weight. Asynchronous means the interface is Future returning throughout, so a cache whose backing store is a network service is not a different kind of object, it is the same object with a different implementation. Eviction policies mean the cache can decide to drop entries, which is a behaviour a plain Map cannot express.

MapCache is the implementation backed by a Map, and it is the one you use in tests, or when you want a cache with a Map's semantics but the Cache interface.

This library is the reason quiver is worth having even if you use nothing else from it. The pattern of injecting a Cache rather than a Map is the standard way to make a repeated lookup cheap and to control how long a value stays valid, and having the interface in a widely used package means the shape of your code matches what other Dart projects expect.

## time: the Clock exists so tests can control the clock

quiver.time is three things, and one of them is a design pattern rather than a function.

Clock provides points in time relative to the current point in time, for example now, 2 days ago, 4 weeks from now. The README makes the argument for using it in one sentence: for testability, use Clock rather than other ways of accessing time, like new DateTime(), so that you can use a fake time function in your tests to control time.

That is the whole point of the library. Code that calls DateTime.now() directly cannot be tested deterministically, and the usual result is a test that passes in February and fails in August, or a test that has to sleep. Injecting a clock makes the passage of time a parameter.

Now is a typedef for functions that return the current time in microseconds, since Clock deals in DateTime which only have millisecond accuracy. The microsecond version exists for the cases where the millisecond resolution of DateTime is not enough.

The unit duration constants are aMicrosecond, aMillisecond, aSecond, aMinute, anHour, aDay and aWeek, and the README gives the comparison that motivates them: aDay against const Duration(days: 1), and aSecond times 30 against const Duration(seconds: 30). The constants are shorter, and the multiplication form reads better than repeating the unit name.

quiver.check sits alongside in spirit even though it is a separate library, with checkArgument throwing an ArgumentError if the specified argument check expression is false, checkListIndex throwing a RangeError if the index is out of bounds, and checkState throwing a StateError if the state check expression is false. Those are the three error types Dart has for the three kinds of failure, and having them named makes the intent of a guard readable.

## The testing libraries are for tests, not production

Quiver also ships testing libraries, and the README is explicit about their scope: they are intended to be used in testing code, not production code, and they consist of fake implementations of some Quiver interfaces.

quiver.testing.async provides FakeAsync, which enables testing of units which depend upon timers and microtasks. It supports fake advancements of time and of the microtask queue, which cause fake timers and microtasks to be processed, and it provides a Clock so the time dependent code under test sees a time you control.

The pairing is the point. A Clock injected into production code and a FakeAsync driving it in a test are two halves of one arrangement, and they only work together if the production code takes its clock as a dependency rather than reaching for a global. That is why quiver.time exists as a separate library from quiver.testing.async, and why the README lists them in different sections.

The same reasoning applies to quiver.cache, where MapCache is the in memory implementation you substitute for a remote backed cache in a test, and to the async library, where a fake stream replaces a socket.

For a team that does not already have a pattern for injecting time, this is the part of quiver that changes how you write code rather than what you can call.

## strings, pattern and what a 2022 release means

The remaining two libraries are small and self-contained.

quiver.strings holds the string helpers Dart does not have: isBlank checking whether a string is null, empty or made of whitespace characters, isNotBlank, isEmpty and isNotEmpty, equalsIgnoreCase and compareIgnoreCase, and loop, which lets you loop through characters in a string starting and ending at arbitrary indices, where out of bounds indices wrap around the string. The README gives the four cases it supports:

```dart
loop('lohel', -3, 2) => 'hello'
loop('la ', 0, 8) => 'la la la' // no trailing space
loop('/path/to/some/file.txt', -3) => 'txt'
loop('top', 3, 0) => 'pot'
```

Rotating, repeating with better character level control, tailing a file extension, and reversing. It is a small function that saves writing four different string slicing helpers.

quiver.pattern is described as pattern.dart container utilities for work with Patterns and RegExps. Glob implements glob patterns that are commonly used with filesystem paths, matchesAny combines multiple Patterns into one and allows for exclusions, matchesFull returns true if a Pattern matches an entire String, and escapeRegex escapes special regex characters in a String so that it can be used as a literal match inside of a RegExp.

quiver.collection is the one to look at if you are choosing a library. It holds listsEqual, mapsEqual and setsEqual for collection equality, indexOf for the first item satisfying a predicate, LruMap, a map that removes the least recently used item when a threshold length is exceeded, Multimap, an associative collection that maps keys to collections of values, BiMap, a bidirectional map with an inverse view allowing lookup of key by value, and TreeSet, a balanced binary tree offering a bidirectional iterator, the ability to iterate from an arbitrary anchor, and nearest search.

Those four collection types are a reimplementation of things the ecosystem has moved on from, and the maintenance record is the reason to think twice. There is no pub.dev release newer than 3.1.0 from 2022-05-03, so a new project is taking a four year old release of a utility package, and the code has been touched since without a new version being published. Check what your Dart SDK constraint allows and whether the pieces you actually want are the ones that have stayed still.

## Conclusion

Adopt quiver for the pieces Dart's core library does not cover, particularly the itertools style combinators in quiver.iterables, the LruMap and Multimap in quiver.collection, and the Clock in quiver.time if you test anything that depends on the current time. Do not adopt it as a general utility grab bag, since each library is separately importable and you should take only the ones you use. Verify first that the version you depend on is compatible with your Dart SDK constraint, that the 2022 release line still satisfies your needs, and that you do not end up with a second Optional type alongside a null safety scheme that already provides one.

## FAQ

### What is quiver for Dart?

Quiver is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality. It is split into independent libraries covering async, cache, check, collection, core, iterables, pattern, strings and time, plus testing libraries with fake implementations.

### How do I use the Clock in quiver to make time dependent code testable?

The README says to use Clock rather than other ways of accessing time such as new DateTime(), so that you can use a fake time function in your tests to control time. The quiver.testing.async library provides FakeAsync, which supports fake advancements of time and of the microtask queue and provides a Clock for the code under test.

### Which collection types does quiver.collection provide?

It provides listsEqual, mapsEqual and setsEqual, indexOf for the first item satisfying a predicate, LruMap which removes the least recently used item when a threshold length is exceeded, Multimap mapping keys to collections of values, BiMap providing an inverse view, and TreeSet, a balanced binary tree with a bidirectional iterator and nearest search.

### Is quiver still being released?

The repository is not archived and the last push was on 2026-04-02, but the published versions are 3.1.0, 3.0.1+2 and 3.0.1+1, all published on 2022-05-03, so the newest release on pub.dev is from 2022.

## Sources

- [google/quiver-dart on GitHub](https://github.com/google/quiver-dart)
- [License: Apache-2.0](https://github.com/google/quiver-dart/blob/master/LICENSE)
- [Project website](https://pub.dev/packages/quiver)
- [README](https://github.com/google/quiver-dart/blob/master/README.md)
- [Releases](https://github.com/google/quiver-dart/releases)

---

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