Swevo.EFCore.Pagination 1.0.2

Prefix Reserved
dotnet add package Swevo.EFCore.Pagination --version 1.0.2
                    
NuGet\Install-Package Swevo.EFCore.Pagination -Version 1.0.2
                    
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="Swevo.EFCore.Pagination" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Swevo.EFCore.Pagination" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Swevo.EFCore.Pagination" />
                    
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 Swevo.EFCore.Pagination --version 1.0.2
                    
#r "nuget: Swevo.EFCore.Pagination, 1.0.2"
                    
#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 Swevo.EFCore.Pagination@1.0.2
                    
#: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=Swevo.EFCore.Pagination&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Swevo.EFCore.Pagination&version=1.0.2
                    
Install as a Cake Tool

Swevo.EFCore.Pagination

NuGet NuGet Downloads CI License: MIT

Offset and cursor-based pagination for EF Core. Two extension methods on IQueryable<T>, two result types — nothing else.

// Offset pagination
var page = await db.Orders
    .Where(o => o.CustomerId == customerId)
    .OrderByDescending(o => o.CreatedAt)
    .ToPageAsync(pageNumber: 1, pageSize: 20);

// page.Items          IReadOnlyList<Order>
// page.TotalCount     int
// page.TotalPages     int
// page.HasNextPage    bool
// page.HasPreviousPage bool

// Cursor (keyset) pagination
var page = await db.Orders
    .Where(o => o.CustomerId == customerId)
    .OrderBy(o => o.Id)
    .ToCursorPageAsync(o => o.Id, afterCursor: cursor, pageSize: 20);

// page.Items       IReadOnlyList<Order>
// page.NextCursor  string?  — pass to the next request
// page.HasNextPage bool

Install

dotnet add package Swevo.EFCore.Pagination

Offset vs cursor

Offset (ToPageAsync) Cursor (ToCursorPageAsync)
Jump to page
Total count
Consistent under inserts
Scalable to millions of rows
Single query ❌ (count + fetch)

Use offset for admin grids with page numbers. Use cursor for infinite-scroll feeds and APIs.

Offset pagination

// GET /orders?page=2&pageSize=20
var page = await db.Orders
    .OrderByDescending(o => o.CreatedAt)
    .ToPageAsync(pageNumber: 2, pageSize: 20, cancellationToken);

return new
{
    items      = page.Items,
    totalCount = page.TotalCount,
    totalPages = page.TotalPages,
    page       = page.PageNumber,
    pageSize   = page.PageSize,
    hasPrev    = page.HasPreviousPage,
    hasNext    = page.HasNextPage,
};
  • pageNumber is 1-based.
  • Issues two SQL queries: COUNT(*) then SELECT ... SKIP ... TAKE.
  • pageSize is capped at 1000.

Cursor (keyset) pagination

// GET /orders?cursor=eyJJZCI6MTAwfQ==&pageSize=20
var page = await db.Orders
    .OrderBy(o => o.Id)          // MUST be ordered by the cursor key
    .ToCursorPageAsync(
        keySelector:  o => o.Id,
        afterCursor:  Request.Query["cursor"],   // null on first page
        pageSize:     20,
        cancellationToken);

return new
{
    items      = page.Items,
    nextCursor = page.NextCursor,   // null on last page
    hasNext    = page.HasNextPage,
};
  • Issues a single SELECT ... WHERE id > ? LIMIT pageSize + 1.
  • Cursor is an opaque Base64-encoded JSON token — do not parse it.
  • Supported key types: int, long, Guid, DateTime, DateTimeOffset, and any value type with a > SQL operator.

Full cursor loop example

string? cursor = null;
do
{
    var page = await db.Products
        .OrderBy(p => p.Id)
        .ToCursorPageAsync(p => p.Id, afterCursor: cursor, pageSize: 100);

    await ProcessBatchAsync(page.Items);
    cursor = page.NextCursor;
} while (cursor is not null);

Part of the Swevo EF Core toolkit

Stack with the other Swevo EF Core packages:

[Auditable]  // → CreatedAt, UpdatedAt
[SoftDelete] // → IsDeleted, global query filter
public partial class Order
{
    public OrderId Id { get; set; } // → Swevo.EFCore.StronglyTyped
}

// Paginate with cursor
var page = await db.Orders
    .OrderBy(o => o.Id)
    .ToCursorPageAsync(o => o.Id, afterCursor: cursor, pageSize: 20);
Package Purpose
Swevo.EFCore.Pagination This package
Swevo.EFCore.StronglyTyped Strongly-typed IDs
Swevo.AutoAudit Audit fields
Swevo.EFCore.SoftDelete Soft delete
Swevo.EFCore.Outbox Transactional outbox

Also by the same author

🌐 Full suite overview: swevo.github.io

Package Description
AutoLog.Generator Compile-time high-performance logging — [Log(Level, Message)] generates LoggerMessage.Define. AOT-safe.
AutoHttpClient.Generator Compile-time typed HTTP client — [HttpClient] on an interface generates a strongly-typed client. AOT-safe Refit alternative.
AutoDispatch.Generator Compile-time CQRS dispatcher — [Handler] generates a strongly-typed IDispatcher. No MediatR, no reflection.
AutoWire Compile-time DI auto-registration — [Scoped]/[Singleton]/[Transient] generates IServiceCollection registration code.
AutoMap.Generator Compile-time object mapping with generated extension methods. AOT-safe AutoMapper alternative.
Package Downloads Description
Swevo.EFCore.Outbox Downloads Transactional outbox pattern for EF Core + AutoBus
Swevo.EFCore.StronglyTyped Downloads Compile-time strongly-typed ID generation for
Swevo.EFCore.SoftDelete Downloads Compile-time soft-delete generation for EF Core entities using Roslyn source generators
Swevo.EFCore.Seeding Downloads Fluent, idempotent, dependency-ordered seed data for EF Core
Swevo.EFCore.JsonColumn Downloads Compile-time JSON column configuration for EF Core 8+ — [JsonColumn] on owned navigation properties generates ConfigureJsonColumns(ModelBuilder) with OwnsOne(
Swevo.EFCore.BulkOperations Downloads Free, MIT-licensed bulk insert/update/delete for EF Core
Swevo.EFCore.MultiTenant Downloads Compile-time multi-tenancy for EF Core
Swevo.EFCore.RowVersion Downloads Compile-time optimistic concurrency for EF Core — [Optimistic] source generator adds RowVersion property, IOptimisticEntity, and SaveChangesClientWinsAsync / SaveChangesDatabaseWinsAsync retry extensions

License

MIT © 2026 Justin Bannister

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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 is compatible.  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.2 88 8/7/2026
1.0.1 158 6/26/2026
1.0.0 111 6/26/2026

1.0.0: ToPageAsync (offset) and ToCursorPageAsync (keyset cursor) IQueryable extension methods. Page<T> and CursorPage<T> result types.