Configure and Verify Pagination in FeathersJS Services
Learn how to enable, customize, and test pagination in FeathersJS services. The guide covers service options, client query syntax, response inspection, and recovery strategies for common pitfalls.
17 Dec 2025, 08:07 UTC

Desired Outcome
By the end of this guide you will be able to:
- Enable pagination on a FeathersJS service with custom limits.
- Send client queries that control page size, offset, and sorting.
- Verify that the service returns the expected
meta.paginationstructure. - Troubleshoot common pagination misconfigurations and roll back if necessary.
Prerequisites
- Node.js 18+ and npm installed.
- FeathersJS project (v6.x recommended). If you’re on v5.x, note the older pagination syntax.
- Database adapter that supports
$skipand$limit(e.g.,feathers-mongoose,feathers-sails,feathers-pg). - Basic understanding of FeathersJS services and REST endpoints.
Step‑by‑Step Procedure
1. Create a Sample Service
npx @feathersjs/cli generate service
# Choose "REST" and "JSON" for simplicity
# Name the service "items"
After generation, the service file (e.g., src/services/items/items.service.js) will contain a create, find, get, etc., methods.
2. Enable Pagination with Custom Limits
Open the service file and modify the options object passed to app.use:
app.use('/items', ItemsService, {
paginate: {
default: 5, // default page size
max: 10, // maximum allowed per request
defaultLimit: 5 // fallback if client omits $limit
}
});
Note: In Feathers v6.x the paginate option accepts an object; in v5.x you can toggle with paginate:true or paginate:false.
3. Seed the Database
Insert 12 test records to observe pagination boundaries:
const items = Array.from({ length: 12 }, (_, i) => ({ name: `Item ${i + 1}` }));
await Promise.all(items.map(item => app.service('items').create(item)));
Run the script with node seed.js or via a Feathers CLI task.
4. Query with Pagination Parameters
Use a REST client (curl, Postman, or a browser) to fetch a specific page:
curl -X GET "http://localhost:3030/items?$limit=3&$skip=6"
Expected JSON snippet:
{
"total": 12,
"limit": 3,
"skip": 6,
"data": [
{"_id":"...","name":"Item 7"},
{"_id":"...","name":"Item 8"},
{"_id":"...","name":"Item 9"}
]
}
The meta.pagination object is flattened into total, limit, and skip fields in the response body.
5. Verify Default Behavior
Send a request without $limit:
curl -X GET "http://localhost:3030/items"
Check that the response contains limit: 5 (our default setting). If you see a different value, verify the service options were applied correctly.
6. Disable Pagination (Optional)
To return all matching records, set paginate: false in the service options:
app.use('/items', ItemsService, { paginate: false });
Re‑run a query and confirm the response lacks any total, limit, or skip fields.
Expected Checks
- Response Structure: Verify the presence of
total,limit, andskipwhen pagination is enabled. - Data Count: The number of items in
datashould not exceedlimit, andskip + data.lengthshould match the requested page. - Database Query Logs: Inspect the adapter logs (e.g.,
console.logor a logger) to ensureLIMITandOFFSETare applied. For MongoDB, look forlimitandskipin the query object. - Boundary Conditions: Request
$limit=15and confirm the service caps it atmax:10. - Sorting & Selecting: Use
$sort=name:1and$select=nameto confirm those options pass through to the adapter.
Recovery Options
- Mis‑configured Limits: If clients receive more data than expected, double‑check the
maxvalue and ensure the adapter supports$limit. - Adapter Incompatibility: Some older adapters may ignore
$skip. Upgrade the adapter or implement a customfindmethod that applies the offset manually. - Performance Bottlenecks: If the service times out, reduce
defaultandmaxlimits or add an index on the queried fields. - Legacy FeathersJS Versions: For v5.x projects, switch to
paginate:trueand adjust your client query accordingly. The response shape differs slightly; consult the v5.x docs.
Version Specific Notes
- Feathers v6.x:
paginateaccepts an object withdefault,max, anddefaultLimit. - Feathers v5.x: Use
paginate:trueorpaginate:false. The response contains ameta.paginationobject instead of flattened fields. - Adapters: Ensure your database driver supports
$skipand$limit. For example,feathers-mongoosetranslates them toskip()andlimit()calls on the Mongoose query.
Practical Checklist
- Confirm service options include
paginatewith desired limits. - Seed data and verify count via
GET /items. - Test edge cases:
$limitbeyondmax,$skipbeyond total, and missing$limit. - Check database logs for correct
LIMITandOFFSETusage. - Document the pagination behavior in your API spec for clients.
Following this workflow ensures your FeathersJS services expose predictable, efficient pagination that scales with your data size.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.