Koa Query Parameter Pagination Middleware
raw JSON →koa-pagination-v2 is a middleware designed for Koa applications to simplify handling pagination logic based on `page` and `limit` query parameters from the request. Currently at version 1.3.2, this package was last published approximately four years ago, indicating it is in a maintenance state rather than active development, with no recent releases or active contribution. Unlike its predecessor or other Koa pagination libraries that might focus on HTTP Range headers (e.g., the original `koa-pagination`), this version specifically processes `page` and `limit` from the URL query string. It exposes computed `limit` and `offset` values, along with a `pageable` helper function, via `ctx.state.paginate`. These values are directly usable with common ORMs (like Sequelize, as shown in the examples) to fetch a subset of data, and the `pageable` function helps construct comprehensive pagination metadata for API responses, including total count, page count, and navigation links. Its key differentiator is its straightforward, query-parameter-based approach, making it easy to integrate for simple REST API pagination.
Common errors
error TypeError: ctx.state.paginate is undefined ↓
app.use(pagination({ /* config */ })); is called *before* any route handlers that depend on pagination data. error Incorrect pagination metadata (e.g., `pageCount` is 1 when it should be higher) ↓
limit and offset for the actual data retrieval, and pass this accurate total to the pageable function. error User-requested `limit` parameter is not respected in the response ↓
maximumLimit option provided when initializing the koa-pagination-v2 middleware. The middleware will cap the limit at this maximum, even if a higher value is requested by the client. Warnings
gotcha This package, `koa-pagination-v2`, processes `page` and `limit` query parameters. Be aware that it is distinct from other `koa-pagination` packages (e.g., `koa-pagination` by Uphold) that parse HTTP `Range` headers for pagination. Using them interchangeably will lead to unexpected behavior. ↓
gotcha The package was last published over four years ago (as of April 2026). While it generally works, it may not receive updates for new Koa versions, Node.js features, or critical security patches. Consider its maintenance status for long-term project viability. ↓
gotcha The `pageable` helper function, exposed on `ctx.state.paginate`, requires the total count of items in the dataset as an argument (`pageable(total)`). If `total` is not provided or is incorrect, the generated `_meta` object in the response will contain inaccurate pagination information (e.g., `pageCount`, `hasNext`). ↓
breaking The configuration options `defaultLimit` and `maximumLimit` affect how `limit` and `offset` are calculated. If `maximumLimit` is set too low, user-requested limits might be silently capped, leading to unexpected results if not communicated to the client. ↓
Install
npm install koa-pagination-v2 yarn add koa-pagination-v2 pnpm add koa-pagination-v2 Imports
- pagination wrong
const pagination = require('koa-pagination-v2');correctimport pagination from 'koa-pagination-v2';
Quickstart
const Koa = require('koa');
const pagination = require('koa-pagination-v2');
const app = new Koa();
// Mock database function for demonstration
const mockFindAndCountAll = async ({ offset, limit }) => {
const allItems = Array.from({ length: 100 }, (_, i) => ({ id: i + 1, name: `Item ${i + 1}` }));
const rows = allItems.slice(offset, offset + limit);
const count = allItems.length;
return { rows, count };
};
app.use(pagination({ defaultLimit: 10, maximumLimit: 50 }));
app.use(async ctx => {
if (ctx.path === '/items') {
const { limit, offset, pageable } = ctx.state.paginate;
const { rows: items, count: total } = await mockFindAndCountAll({
offset,
limit
});
ctx.body = {
data: items,
_meta: pageable(total) // Pass the total count to generate meta-data
};
} else {
ctx.body = 'Visit /items?page=1&limit=10 for pagination example.';
}
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
console.log(`Try: http://localhost:${port}/items?page=1&limit=5`);
console.log(`Try: http://localhost:${port}/items?page=2&limit=5`);
console.log(`Try: http://localhost:${port}/items?page=1&limit=60 (will cap at maxLimit of 50)`);
});