Swevo.EFCore.Pagination 1.0.1

Prefix Reserved
dotnet add package Swevo.EFCore.Pagination --version 1.0.1
                    
NuGet\Install-Package Swevo.EFCore.Pagination -Version 1.0.1
                    
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.1" />
                    
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.1" />
                    
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.1
                    
#r "nuget: Swevo.EFCore.Pagination, 1.0.1"
                    
#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.1
                    
#: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.1
                    
Install as a Cake Addin
#tool nuget:?package=Swevo.EFCore.Pagination&version=1.0.1
                    
Install as a Cake Tool

Swevo.EFCore.Pagination

NuGet CI

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

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 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.1 123 6/26/2026
1.0.0 95 6/26/2026

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