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" />
<PackageReference Include="Swevo.EFCore.Pagination" />
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
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#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
#tool nuget:?package=Swevo.EFCore.Pagination&version=1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Swevo.EFCore.Pagination
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,
};
pageNumberis 1-based.- Issues two SQL queries:
COUNT(*)thenSELECT ... SKIP ... TAKE. pageSizeis 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 | Versions 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.
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.28)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.0: ToPageAsync (offset) and ToCursorPageAsync (keyset cursor) IQueryable extension methods. Page<T> and CursorPage<T> result types.