Library / SDK
App-vNext/Polly avatar
App-vNext/Polly

Polly: Resilience Pipelines for .NET Services

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. From version 6.0.1, Polly targets .NET Standard 1.1 and 2.0+.

14,237 stars1,288 forksC#BSD-3-Clause

At a glance

What is it?
Polly is the .NET Foundation library that turns retry, timeout, circuit breaker, rate limiter and fallback into composable resilience pipelines. It is a good fit for teams running .NET services against flaky dependencies, and a poor fit for anyone who wants a framework to decide their failure policy for them.
Who is it for?
Adopt Polly if you run .NET services that call dependencies you do not control and you want the failure policy expressed in code rather than in a wiki page. Do not adopt it if you expect the library to choose sensible retry counts, timeouts or breaker thresholds for you: the defaults are starting points, and the composition order is your decision.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Polly solves for .NET service authors

A service that calls another service over the network inherits every failure mode of that network. Connections are refused, DNS lookups time out, a downstream dependency starts returning 503s for thirty seconds, a database hits its connection ceiling. The code that handles these cases is tedious and easy to get wrong: a retry loop that forgets jitter, a timeout that is never applied to the actual I/O call, a breaker that never closes again.

Polly addresses that by making each failure-handling decision an object you configure and then compose. The README describes the library as one that lets developers express resilience strategies such as Retry, Circuit Breaker, Hedging, Timeout, Rate Limiter and Fallback in a fluent and thread-safe manner. The audience is .NET developers who own the calling side of an integration and want the policy visible in source control rather than in an operations runbook.

It is not a service mesh, a proxy or a scheduler. It does not sit between your process and the network. It runs inside your process, around a delegate you hand it, which means it only protects calls you route through it.

How a ResiliencePipeline composes strategies

The v8 model has three moving parts. A callback is the work you want to protect. A strategy is one policy such as retry or timeout. A resilience pipeline is a combination of one or more strategies. The README states that Polly uses builders to integrate strategies into a pipeline.

The builder returns an immutable pipeline. You add strategies in the order you want them to wrap the callback, then call Build. The README's quick start adds a retry with default options and a ten second timeout, and the resulting pipeline is executed with ExecuteAsync. The pipeline is thread-safe, so the same instance can be shared across concurrent requests rather than rebuilt per call.

There is a second way to define pipelines. With the Polly.Extensions package you register a named pipeline on an IServiceCollection using AddResiliencePipeline, then resolve a ResiliencePipelineProvider and ask it for the pipeline by name. The README notes that the provider dynamically creates and caches resilience pipelines. That caching detail matters: the pipeline is not rebuilt on every resolution, so configuration is fixed at registration time.

The strategy list is broader than retry and timeout. Circuit breaker, hedging, rate limiter and fallback are all in the same builder vocabulary, and Polly.RateLimiting integrates with the System.Threading.RateLimiting APIs rather than defining its own limiter type.

Installing Polly.Core and running a first pipeline

Polly ships as several NuGet packages rather than one. Polly.Core holds the core abstractions and the built-in strategies. Polly.Extensions adds telemetry and dependency injection support. Polly.RateLimiting wires in System.Threading.RateLimiting. Polly.Testing adds testing support. The package named simply Polly contains the legacy API exposed by versions of the library before version 8, so a project that adds Polly and expects the v8 builder will be surprised.

Start by adding the core package to your project.

bash
dotnet add package Polly.Core

The README's quick start builds a pipeline from a ResiliencePipelineBuilder, adds a retry with default options and a ten second timeout, then builds it.

cs
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()
    .AddRetry(new RetryStrategyOptions())
    .AddTimeout(TimeSpan.FromSeconds(10))
    .Build();

await pipeline.ExecuteAsync(static async token => { /* Your custom logic goes here */ }, cancellationToken);

After Build you hold a ResiliencePipeline. Every call you want protected goes through ExecuteAsync, and the callback receives a cancellation token that the timeout strategy can cancel. If your callback ignores that token, the timeout cannot interrupt it.

If you would rather register pipelines through the DI container, add the extensions package first.

bash
dotnet add package Polly.Extensions

Then register the pipeline by name and resolve it through the provider.

cs
var services = new ServiceCollection();

services.AddResiliencePipeline("my-pipeline", builder =>
{
    builder
        .AddRetry(new RetryStrategyOptions())
        .AddTimeout(TimeSpan.FromSeconds(10));
});

var serviceProvider = services.BuildServiceProvider();
var pipelineProvider = serviceProvider.GetRequiredService<ResiliencePipelineProvider<string>>();
ResiliencePipeline pipeline = pipelineProvider.GetPipeline("my-pipeline");

The string "my-pipeline" is the registration key, and the same string is passed to GetPipeline. The generic parameter on ResiliencePipelineProvider is the key type, so an enum key type is possible if you prefer compile-time names. The README does not document what happens when you request a name that was never registered, so treat that as unverified and check the pollydocs.org pages on pipelines before relying on any particular exception.

Where Polly is the wrong tool

Polly protects in-process calls. If your failure is a slow query inside a database driver, a retry strategy around the query will re-run the query, not cancel it. If your callback blocks a thread and never observes the cancellation token, the timeout strategy has nothing to cancel. Those are not library defects; they are the boundary of what an in-process policy can do.

Composition order is the second trap. The README shows retry added before timeout, which means the timeout applies inside each retry attempt. Reverse the order and the timeout wraps the whole retry sequence instead. Both are legitimate, and they produce different behaviour under load. The library will not warn you. This is the main reason Polly rewards teams that write down what they intend: the builder is fluent enough that a wrong order compiles and runs.

There is also a scope question. If you need retries, timeouts and circuit breaking for services written in several languages, or you want the policy enforced outside the application process so that a crashed service still gets protected, an in-process library is the wrong layer. Polly is a .NET library and the README frames it as one.

Finally, the maintenance model changed. The README states that Polly participates in the Open Source Maintenance Fee, and that from November 16, 2026 companies earning at least US $20,000 from a product or project that uses Polly will be asked to pay a US $20/month maintenance fee. The source stays free and open, and individuals, hobbyists and organisations below the threshold owe nothing. That is a policy fact to check against your own revenue accounting, not a licensing change to the BSD-3-Clause terms.

Polly compared with writing your own retry loop

The obvious alternative is a hand-written loop: a for statement, a try/catch, a Task.Delay between attempts. For one call site with one failure mode, that is a reasonable amount of code and it has no dependency. The difference in approach shows up as the number of policies grows.

A hand-written loop handles retry. It does not give you a circuit breaker that trips after a failure ratio and then half-opens to probe recovery, nor a hedging strategy that starts a second attempt before the first has failed, nor a rate limiter tied to System.Threading.RateLimiting. Each of those is a separate concurrency problem, and the breaker in particular is stateful across requests, which means it needs to be shared and thread-safe. Polly's answer is to keep that state inside the strategy object and expose it through the same builder API.

The other difference is testability and observability. Polly.Testing exists as a package specifically to support testing Polly libraries, and Polly.Extensions carries telemetry support. A hand-rolled loop gives you whatever logging you remember to add. If your service already has OpenTelemetry instrumentation, the telemetry path in the extensions package is the argument for using the library rather than a loop.

What a loop gives you that Polly does not is total freedom over the control flow. If your retry decision depends on a business rule that no strategy option expresses, you will end up writing a custom strategy or dropping back to a loop anyway.

Maintenance, releases and upgrade cost

The repository is not archived, and the last push was on 2026-09-19. Releases are frequent enough to track: 8.8.0 on 2026-09-14, 8.7.0 on 2026-06-08, and 8.6.6 on 2026-03-04. A team adopting Polly should expect to move minor versions a few times a year.

The larger upgrade cost is the v7 to v8 transition, and it is not a package bump. The README states plainly that the documentation describes the new Polly v8 API and that v7 users should refer to the previous version of the documentation, linked as the 7.2.4 tree. The package split reflects this: Polly.Core and Polly.Extensions are the v8 world, while the Polly package holds the legacy pre-v8 API. Code written against the old Policy and AsyncPolicy types does not compile against ResiliencePipelineBuilder without rework.

On licensing, the code is BSD-3-Clause, which permits commercial use and modification. The Open Source Maintenance Fee is a separate ask layered on top, with a stated threshold of US $20,000 of revenue and a US $20/month fee from November 16, 2026. That is a commercial and governance question for your organisation, and it is not legal advice; read the announcement linked from the README and decide with whoever owns your open source policy. The practical upgrade advice is narrow: pin the package versions you depend on, and read the changelog before taking a new minor, because the strategy options surface has been moving across the 8.x line.

Editorial conclusion

Adopt Polly if you run .NET services that call dependencies you do not control and you want the failure policy expressed in code rather than in a wiki page. Do not adopt it if you expect the library to choose sensible retry counts, timeouts or breaker thresholds for you: the defaults are starting points, and the composition order is your decision. Before committing, verify two things. First, whether your organisation crosses the Open Source Maintenance Fee threshold of US $20,000 of revenue from a product that uses Polly, since the fee starts on November 16, 2026. Second, whether you are on the v8 API or the legacy v7 API, because the README documents v8 and points v7 users at the 7.2.4 documentation tree.

Frequently asked questions

How do I install Polly in a .NET project?

Add the Polly.Core package with the dotnet CLI, which the README gives as dotnet add package Polly.Core. Add Polly.Extensions as well if you want dependency injection and telemetry support.

What is Polly used for in .NET?

It expresses resilience strategies such as Retry, Circuit Breaker, Hedging, Timeout, Rate Limiter and Fallback around a callback. The strategies are composed into a resilience pipeline that you execute instead of calling the callback directly.

How do I use Polly in code?

Build a ResiliencePipeline from a ResiliencePipelineBuilder, add the strategies you want, call Build, and run your callback through ExecuteAsync. Alternatively register a named pipeline with AddResiliencePipeline and resolve it from a ResiliencePipelineProvider.

Official sources

  1. App-vNext/Polly on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/app-vnext-polly.svg)](https://hysenlabs.com/projects/app-vnext-polly)