PollyNpgsql 1.0.0

dotnet add package PollyNpgsql --version 1.0.0
                    
NuGet\Install-Package PollyNpgsql -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PollyNpgsql" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PollyNpgsql" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PollyNpgsql" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PollyNpgsql --version 1.0.0
                    
#r "nuget: PollyNpgsql, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PollyNpgsql@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PollyNpgsql&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PollyNpgsql&version=1.0.0
                    
Install as a Cake Tool

PollyNpgsql

NuGet NuGet Downloads CI

Polly v8 resilience for Npgsql (PostgreSQL) — retry, timeout, and circuit-breaker for NpgsqlConnection queries and commands, plus a built-in PostgresTransientErrors predicate covering all common PostgreSQL transient SQLSTATE codes. Zero changes to your existing SQL.

// One line of setup
var resilient = connection.WithPolly(pipeline =>
    pipeline
        .AddRetry(new RetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            ShouldHandle = PostgresTransientErrors.IsTransient, // built-in ✔
        })
        .AddTimeout(TimeSpan.FromSeconds(10)));

// Use exactly like NpgsqlConnection
var orders = await resilient.QueryAsync(
    "SELECT id, total FROM orders WHERE customer_id = $1",
    r => new Order(r.GetInt32(0), r.GetDecimal(1)),
    parameters: [new NpgsqlParameter { Value = customerId }]);

Installation

dotnet add package PollyNpgsql

Targets net6.0, net8.0, and net9.0. Dependencies: Polly.Core 8.*, Npgsql 9.*, Microsoft.Extensions.DependencyInjection.Abstractions 8.*


PostgresTransientErrors — the key feature

Knowing which PostgreSQL errors are safe to retry is the hard part. PollyNpgsql ships a pre-built PostgresTransientErrors.IsTransient predicate so you don't have to look up SQLSTATE codes.

new RetryStrategyOptions
{
    MaxRetryAttempts = 3,
    ShouldHandle = PostgresTransientErrors.IsTransient,
}
SQLSTATE Name When it occurs
40001 serialization_failure Concurrent transaction conflict
40P01 deadlock_detected Two transactions blocking each other
53300 too_many_connections Connection pool exhausted
53400 configuration_limit_exceeded Resource limit hit
57P03 cannot_connect_now Server starting up or shutting down
08000 connection_exception General connection error
08006 connection_failure Connection dropped mid-query
08001 sqlclient_unable_to_establish_sqlconnection Cannot reach server
08004 sqlserver_rejected_establishment_of_sqlconnection Server rejected connection

The raw set is also available if you need to extend it:

// Add custom codes
var myStates = PostgresTransientErrors.SqlStates.ToHashSet();
myStates.Add("57014"); // query_canceled (e.g. statement_timeout)

new RetryStrategyOptions
{
    ShouldHandle = new PredicateBuilder().Handle<NpgsqlException>(ex =>
        ex is PostgresException pg && myStates.Contains(pg.SqlState))
}

Quick start

Inline pipeline

using PollyNpgsql;

await using var connection = new NpgsqlConnection(connectionString);
var resilient = connection.WithPolly(pipeline =>
    pipeline
        .AddRetry(new RetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            Delay = TimeSpan.FromMilliseconds(200),
            BackoffType = DelayBackoffType.Exponential,
            ShouldHandle = PostgresTransientErrors.IsTransient,
        })
        .AddTimeout(TimeSpan.FromSeconds(30)));

await resilient.OpenAsync();

// Execute non-query
await resilient.ExecuteAsync(
    "INSERT INTO events (type, payload) VALUES ($1, $2)",
    parameters: [new("type") { Value = "OrderPlaced" }, new("payload") { Value = json }]);

// Query with mapper
var orders = await resilient.QueryAsync(
    "SELECT id, total FROM orders WHERE customer_id = $1",
    reader => new Order(reader.GetInt32(0), reader.GetDecimal(1)),
    parameters: [new NpgsqlParameter { Value = customerId }]);

// Scalar
var count = await resilient.ExecuteScalarAsync<long>("SELECT COUNT(*) FROM orders");

Dependency injection

// Program.cs
builder.Services.AddScoped(_ => new NpgsqlConnection(connectionString));

builder.Services.AddPollyNpgsql(pipeline =>
    pipeline
        .AddRetry(new RetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            Delay = TimeSpan.FromMilliseconds(200),
            BackoffType = DelayBackoffType.Exponential,
            ShouldHandle = PostgresTransientErrors.IsTransient,
        })
        .AddTimeout(TimeSpan.FromSeconds(30))
        .AddCircuitBreaker(new CircuitBreakerStrategyOptions
        {
            FailureRatio = 0.5,
            MinimumThroughput = 10,
            SamplingDuration = TimeSpan.FromSeconds(30),
            BreakDuration = TimeSpan.FromSeconds(15),
        }));

// Repository
public class OrderRepository(NpgsqlConnection db, ResiliencePipeline pipeline)
{
    public async Task<List<Order>> GetByCustomerAsync(int customerId)
    {
        var resilient = db.WithPolly(pipeline);
        await resilient.OpenAsync();
        return await resilient.QueryAsync(
            "SELECT id, total FROM orders WHERE customer_id = $1",
            r => new Order(r.GetInt32(0), r.GetDecimal(1)),
            parameters: [new NpgsqlParameter { Value = customerId }]);
    }
}

Supported operations

Method Description
OpenAsync Open the connection with retry
ExecuteAsync Execute non-query, returns rows affected
ExecuteScalarAsync<T> Execute scalar, returns first column of first row
QueryAsync<T> Query with row mapper, returns List<T>
QueryFirstOrDefaultAsync<T> Query with row mapper, returns first row or default

Pipeline order

[Timeout] → [Retry] → [Circuit Breaker] → [Npgsql]
pipeline
    .AddTimeout(TimeSpan.FromSeconds(30))   // 1. Overall deadline
    .AddRetry(retryOptions)                 // 2. Retry transient failures
    .AddCircuitBreaker(cbOptions)           // 3. Open circuit under load

Package Downloads Description
PollyDapper Downloads Polly v8 resilience for Dapper (works with any IDbConnection including Npgsql)
PollyEFCore Downloads Polly v8 resilience for EF Core queries and SaveChanges
PollyMongo Downloads Polly v8 resilience for MongoDB.Driver
PollyAzureBlob Downloads Polly v8 resilience for Azure Blob Storage
PollyRedis Downloads Polly v8 resilience for StackExchange.Redis
PollyMediatR Downloads Polly v8 resilience pipelines for MediatR
PollyAzureServiceBus Downloads Polly v8 resilience for Azure Service Bus
PollyHealthChecks Downloads ASP.NET Core health checks for Polly v8 circuit breakers
PollyBackoff Downloads Jitter, linear & custom backoff for Polly v8 retry

License

MIT

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 51 6/24/2026

1.0.0: Initial release. ResilientNpgsqlConnection wraps Npgsql queries and commands in a Polly v8 ResiliencePipeline. Includes PostgresTransientErrors helper with pre-built ShouldHandle predicate. Supports net6.0, net8.0, and net9.0.