Skip to content
Buy me a coffee

Bundle size

Every strategy is a separate, side-effect-free module ("sideEffects": false). Your bundler includes only the ones you import. The one exception is the convenience builder, which references all of them.

Measured min+gzip for the browser with esbuild. Budgets are enforced by npm run check:size:

What you use Size
retry() one-liner 4.1 KB
PipelineBuilder + retry + timeout 4.8 KB
PipelineBuilder + retry + circuit breaker + timeout 7.1 KB
createResilientFetch() (/fetch, per-host breakers) 9.1 KB
ResiliencePipelineBuilder (every strategy) 15.1 KB

Per-scenario numbers for more setups are in Bundle sizes.

ResiliencePipelineBuilder has an addX() method for every strategy, so importing it pulls in every strategy. PipelineBuilder has only add(); you pass it strategy definitions, and only those are bundled:

import {
class PipelineBuilder<T = any, E = never, Caught extends string = never>

The minimal builder: only the strategies you add end up in your bundle.

import { PipelineBuilder, retryStrategy, timeoutStrategy } from '@ylcnfrht/resilience';
const pipeline = new PipelineBuilder().add(retryStrategy({ maxRetryAttempts: 3 })).add(timeoutStrategy('2s')).build();

ResiliencePipelineBuilder adds Polly-style addRetry() / addTimeout() / … shortcuts on top, at the cost of bundling every strategy. Strategies run in the order they are added: the first one added is the outermost. Options are validated and strategy state (e.g. circuit breaker) is created on build().

PipelineBuilder
,
const retryStrategy: <T = any>(options?: RetryOptions<T>) => StrategyDefinition<T>

new PipelineBuilder().add(retryStrategy({ ... })): same as addRetry, but only bundles retry.

retryStrategy
,
const circuitBreakerStrategy: <T = any>(options?: CircuitBreakerOptions<T>) => StrategyDefinition<T, BrokenCircuitError>
circuitBreakerStrategy
,
const timeoutStrategy: <T = any>(options: Duration | TimeoutOptions) => StrategyDefinition<T, TimeoutRejectedError>

timeoutStrategy(5000), timeoutStrategy('5s') or timeoutStrategy({ timeout: '5s', onTimeout }).

timeoutStrategy
} from '@ylcnfrht/resilience';
const
const pipeline: ResiliencePipeline<any, WithErrors<BrokenCircuitError, never, TimeoutRejectedError>>
pipeline
= new
new PipelineBuilder<any, never, never>(options?: ResiliencePipelineBuilderOptions): PipelineBuilder<any, never, never>

The minimal builder: only the strategies you add end up in your bundle.

import { PipelineBuilder, retryStrategy, timeoutStrategy } from '@ylcnfrht/resilience';
const pipeline = new PipelineBuilder().add(retryStrategy({ maxRetryAttempts: 3 })).add(timeoutStrategy('2s')).build();

ResiliencePipelineBuilder adds Polly-style addRetry() / addTimeout() / … shortcuts on top, at the cost of bundling every strategy. Strategies run in the order they are added: the first one added is the outermost. Options are validated and strategy state (e.g. circuit breaker) is created on build().

PipelineBuilder
({
ResiliencePipelineBuilderOptions.name?: string | undefined

Labels telemetry events.

name
: 'api' })
.
PipelineBuilder<any, never, never>.add<StrategyDefinition<any, never>>(definition: StrategyDefinition<any, never>): PipelineBuilder<any, never, never>
add
(
retryStrategy<any>(options?: RetryOptions<any>): StrategyDefinition<any, never>

new PipelineBuilder().add(retryStrategy({ ... })): same as addRetry, but only bundles retry.

retryStrategy
({
RetryOptions<T>.maxRetryAttempts?: number | undefined

Retries in addition to the original call. Default 3. Infinity retries until aborted.

maxRetryAttempts
: 3,
RetryOptions<T>.backoffType?: BackoffType | undefined

Default 'constant'.

backoffType
: 'exponential' }))
.
PipelineBuilder<any, never, never>.add<StrategyDefinition<any, BrokenCircuitError>>(definition: StrategyDefinition<any, BrokenCircuitError>): PipelineBuilder<any, BrokenCircuitError, never>
add
(
circuitBreakerStrategy<any>(options?: CircuitBreakerOptions<any>): StrategyDefinition<any, BrokenCircuitError>
circuitBreakerStrategy
({
CircuitBreakerOptions<T>.consecutiveFailures?: number | undefined

Break after this many failures in a row (a success resets the count). Simple and good for low traffic. When set without failureRatio, the ratio check is off and only this rule applies.

consecutiveFailures
: 5 }))
.
PipelineBuilder<any, BrokenCircuitError, never>.add<StrategyDefinition<any, TimeoutRejectedError>>(definition: StrategyDefinition<any, TimeoutRejectedError>): PipelineBuilder<any, WithErrors<BrokenCircuitError, never, TimeoutRejectedError>, never>
add
(
timeoutStrategy<any>(options: Duration | TimeoutOptions): StrategyDefinition<any, TimeoutRejectedError>

timeoutStrategy(5000), timeoutStrategy('5s') or timeoutStrategy({ timeout: '5s', onTimeout }).

timeoutStrategy
('2s'))
.
PipelineBuilder<any, WithErrors<BrokenCircuitError, never, TimeoutRejectedError>, never>.build(): ResiliencePipeline<any, WithErrors<BrokenCircuitError, never, TimeoutRejectedError>>
build
();

The resulting pipeline is identical, typed errors included. Every addX() has an xStrategy() counterpart:

Builder method Definition
addRetry retryStrategy
addTimeout timeoutStrategy
addCircuitBreaker circuitBreakerStrategy
addFallback / addFallbackOn / addMapError fallbackStrategy / fallbackOnStrategy / mapErrorStrategy
addStaleFallback staleFallbackStrategy
addHedging hedgingStrategy
addConcurrencyLimiter concurrencyLimiterStrategy
addAdaptiveConcurrencyLimiter adaptiveConcurrencyLimiterStrategy
addRateLimiter tokenBucketStrategy
addFixedWindowRateLimiter / addSlidingWindowRateLimiter fixedWindowRateLimiterStrategy / slidingWindowRateLimiterStrategy
addPartitionedRateLimiter partitionedRateLimiterStrategy
addCache / addCoalesce cacheStrategy / coalesceStrategy
addLock lockStrategy
addChaosFault / addChaosOutcome / addChaosLatency / addChaosBehavior chaosFaultStrategy / chaosOutcomeStrategy / chaosLatencyStrategy / chaosBehaviorStrategy
  • One strategy, no pipeline: retry() and withTimeout() build their strategy directly, without a builder.
  • Code that only consumes results (a UI layer handling settle() outcomes): import from @ylcnfrht/resilience/outcome. It has Outcome, the error classes and the guards, and no strategy.
  • Pass predicates as functions when size matters. PredicateBuilder is only bundled if you use it.
  • Circuit breaker extensions (circuitHealthCheck, sharedCircuitState) are separate modules, bundled only when you pass them in extensions.
  • Integrations live in subpaths (/fetch, /otel, /nestjs…). The main entry never imports framework code.