NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #1906 most downloaded on pub.dev
Either monad for Dart language and Flutter framework. Type-safe error handling, railway oriented programming. Supports Monad comprehensions, async map, async flatMap.
Last release 1 months ago
06 Sep 2026
Release timing varies
gaps range from 8 days to 2.0 years
Nearly every release is documented
notes for 7 of 7 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
13 releases · first in 2021
https://pub.dev/packages/dart_either/versions/2.4.0
Relocated flatMap, getOrElse, getOrHandle, handleError,
and handleErrorWith from Either instance members to exported generic extensions.
dynamic receivers no longer dispatch to these operations.Split every value-operation extension exported by either_extensions.dart
into a method-named source file. This file split changes only the source
layout; public exports, call syntax, and behavior remain unchanged, so no
consumer migration is required for the split.
Either.parSequenceN and Either.parTraverseNFixed Either.parSequenceN and Either.parTraverseN with finite concurrency
so functions still waiting for a permit are not invoked after the first
observed Left, thrown error, or failed future.
Left is returned when it is observed first;A non-null maxConcurrent less than or equal to zero now throws an
ArgumentError synchronously, before inputs are traversed, the
parTraverseN mapper is called, or callbacks are invoked.
Errors thrown while iterating the input or invoking the parTraverseN
mapper now propagate synchronously instead of completing the returned future
with an error. No asynchronous operation callback is invoked if this input
preparation fails.
Full Changelog: 2.3.0...2.4.0
One column per quarter.
Deprecated catchError in favor of tryCatch .
Added isLeftAnd, which evaluates a predicate for Left values and returns
false for Right values.
Added tryCatch and tryCatchAsync as the canonical synchronous and
asynchronous error-capture APIs. Both use required named action and
errorMapper parameters. tryCatchAsync captures errors thrown before a
future is returned as well as errors that complete the future.
catchError in favor of tryCatch.catchFutureError in favor of tryCatchAsync.catchStreamError in favor of Stream.toEitherStream.2.x.Added registerFatalError<T>() to exclude a registered error type and its
subtypes from conversion to Left. Registered errors retain their original
error and stack trace across tryCatch, tryCatchAsync,
Future.toEitherFuture, and Stream.toEitherStream.
Registration is per isolate, additive, and idempotent; spawned isolates must
register their own fatal types.
Added bindingAsync as the canonical asynchronous counterpart to binding.
Deprecated futureBinding in favor of bindingAsync; the alias retains its
existing call syntax and behavior throughout 2.x.
Fixed handleError to preserve the original Right instance instead of
creating an equivalent one. Callback invocation and Left recovery behavior
are unchanged.
Clarified the channel and callback semantics of handleErrorWith,
handleError, redeem, and redeemWith.
Full Changelog: 2.2.0...2.3.0
Deprecated aliases remain: tapLeft → onLeft , tap → onRight .
EitheronLeft and onRight; each runs an action on one side and returnsEither.tapLeft → onLeft, tap → onRight.isRightAnd to match a Right value with a predicate.exists remains as a deprecated alias.getOrNull for Right and leftOrNull for Left.orNull remains as a deprecated alias of getOrNull.getOrDefault(value).getOrElse(() => value); use getOrDefault for an eagergetOrHandle((left) => value) for a lazy, left-aware fallback.combine: combine matching sides; otherwise return the sole Left.flatten: convert Either<L, Either<L, R>> to Either<L, R>.merge: extract the value from Either<T, T>.EitherEffect, Either.binding, and Either.futureBindingeffect.raise(left) to exit the owning scope with Left(left).Left and returns Never, so it works innullable ?? effect.raise('missing').ensure and ensureNotNull now delegate their short-circuit paths toraise.EitherEffect<L> from a covariant public class into an opaque,bind moved from an instance member to BindEitherEffectExtension.effect.bind(either) unchanged. PrefixedStateError.StateError instead of producing Right.EitherEffect.bindThe usual unprefixed package import keeps the existing call syntax. With a
prefixed import, invoke the named extension explicitly:
import 'package:dart_either/dart_either.dart' as de;
final result = de.Either<String, int>.binding((effect) {
return de.BindEitherEffectExtension(effect).bind(
de.Either<String, int>.right(1),
);
});For a selective unprefixed import, include BindEitherEffectExtension in the
show list. The Dart SDK constraint remains >=3.0.0 <4.0.0.
EitherEffect construction;Full Changelog: 2.1.0...2.2.0
https://pub.dev/packages/dart_either/versions/2.1.0
Either.parSequenceN and Either.parTraverseN from experimental to stable.Either.parSequenceN and Either.parTraverseN.Either.parSequenceN and Either.parTraverseN, including concurrency-limit and short-circuit cases.@useResult annotations to public APIs that should not be ignored (for example: isLeft, isRight, map, flatMap, swap, exists, all, toEitherStream, left, right, and others).Either.parSequenceN changed from positional parameters to named parameters:
// Before (2.0.0)
Either.parSequenceN<String, int>(functions, n);
// Now (2.1.0)
Either.parSequenceN<String, int>(
functions: functions,
maxConcurrent: n,
);Either.parTraverseN changed from positional parameters to named parameters:
// Before (2.0.0)
Either.parTraverseN<String, int, int>(values, mapper, n);
// Now (2.1.0)
Either.parTraverseN<String, int, int>(
values: values,
mapper: mapper,
maxConcurrent: n,
);maxConcurrent controls concurrency.
2) to limit concurrency.null for unlimited concurrency.https://pub.dev/packages/dart_either/versions/2.0.0
Require Dart 3.0.0 or higher >=3.0.0 <4.0.0.
Make Either a sealed class, EitherEffect a sealed class, and ControlError a final class.
Now you can use exhaustive switch expressions on Either instances.
final Either<String, int> either = Either.right(10);
// Use the `when` method to handle
either.when(
ifLeft: (l) => print('Left: $l'),
ifRight: (r) => print('Right: $r'),
); // Prints Right: Either.Right(10)
// Or use Dart 3.0 switch expression syntax 🤘
print(
switch (either) {
Left() => 'Left: $either',
Right() => 'Right: $either',
},
); // Prints Right: Either.Right(10)Full Changelog: 1.0.0...2.0.0
Require Dart 3.0.0 or higher >=3.0.0 <4.0.0.
Make Either a sealed class, EitherEffect a sealed class, and ControlError a final class.
Now you can use exhaustive switch expressions on Either instances.
final Either<String, int> either = Either.right(10);
// Use the `when` method to handle
either.when(
ifLeft: (l) => print('Left: $l'),
ifRight: (r) => print('Right: $r'),
); // Prints Right: Either.Right(10)
// Or use Dart 3.0 switch expression syntax 🤘
print(
switch (either) {
Left() => 'Left: $either',
Right() => 'Right: $either',
},
); // Prints Right: Either.Right(10)
https://pub.dev/packages/dart_either/versions/1.0.0
Full Changelog: 0.0.1...1.0.0
Full Changelog : 1.0.0-beta05...1.0.0-beta06
Full Changelog: 1.0.0-beta05...1.0.0-beta06
Full Changelog : 1.0.0-beta04...1.0.0-beta05
Full Changelog: 1.0.0-beta04...1.0.0-beta05
refactor impl by @hoc081098 in #10
TBD Full Changelog : 1.0.0-beta02...1.0.0-beta03
TBD
Full Changelog: 1.0.0-beta02...1.0.0-beta03
TBD Full Changelog : 1.0.0-beta01...1.0.0-beta02
TBD
Full Changelog: 1.0.0-beta01...1.0.0-beta02
TBD Full Changelog : 0.0.1...1.0.0-beta01
TBD
Full Changelog: 0.0.1...1.0.0-beta01
Initial version, created by Stagehand
Your coding agent can read these notes before it upgrades. Set up the MCP server →