ddnexus/pagy
π The Best Pagination Ruby Gem π₯
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained β safe to depend on.
Has a license, tests, and CI β clean foundation to fork and modify.
Documented and popular β useful reference codebase to read through.
No critical CVEs, sane security posture β runnable as-is.
- βLast commit 2d ago
- β8 active contributors
- βMIT licensed
Show 3 more βShow less
- βCI configured
- βTests present
- β Single-maintainer risk β top contributor 92% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README β live-updates from the latest cached analysis.
[](https://repopilot.app/r/ddnexus/pagy)Paste at the top of your README.md β renders inline like a shields.io badge.
βΈPreview social card (1200Γ630)
This card auto-renders when someone shares https://repopilot.app/r/ddnexus/pagy on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ddnexus/pagy
Generated by RepoPilot Β· 2026-05-10 Β· Source
π€Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale β STOP and ask the user to regenerate it before proceeding. - Treat the AI Β· unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ddnexus/pagy shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything β but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
π―Verdict
GO β Healthy across all four use cases
- Last commit 2d ago
- 8 active contributors
- MIT licensed
- CI configured
- Tests present
- β Single-maintainer risk β top contributor 92% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
β Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ddnexus/pagy
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale β regenerate it at
repopilot.app/r/ddnexus/pagy.
What it runs against: a local clone of ddnexus/pagy β the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ddnexus/pagy | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | Last commit β€ 32 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ddnexus/pagy. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ddnexus/pagy.git
# cd pagy
#
# Then paste this script. Every check is read-only β no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ddnexus/pagy and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ddnexus/pagy(\\.git)?\\b" \\
&& ok "origin remote is ddnexus/pagy" \\
|| miss "origin remote is not ddnexus/pagy (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift β was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
miss "last commit was $days_since_last days ago β artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) β safe to trust"
else
echo "artifact has $fail stale claim(s) β regenerate at https://repopilot.app/r/ddnexus/pagy"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
β‘TL;DR
Pagy is a high-performance pagination Ruby gem that handles offset-based, keyset-based, and hybrid counting strategies for Rails and other frameworks. It provides framework-agnostic pagination logic with minimal setup, auto-configuring itself to detect ORM type (ActiveRecord, Sequel, etc.) and rendering navs for Bootstrap, Bulma, and custom CSS frameworks. The core differentiator is its speedβit eliminates expensive COUNT queries and supports the exclusive keynav_js technique for instant pagination without page numbers. Single monorepo: Ruby core at lib/pagy/ (414KB Ruby), JavaScript utilities in app/pagy/ (59KB JS) and app/pagy/stylesheets/ (5KB CSS), TypeScript helpers in src/ (58KB TS). Paginators live in lib/pagy/paginators/ (offset, keyset, countish, keynav_js). Config is in config/pagy.rb; navs are auto-loaded per framework. .run/ contains IDE run configurations for different test/demo modes.
π₯Who it's for
Rails developers building data-heavy applications who need pagination without the bloat of kaminari or will_paginate. Specifically: backend engineers optimizing query performance, API developers serving paginated endpoints, and frontend teams using Pagy's JS components for interactive navigation (keynav, input_nav_js). Also framework maintainers adding pagination support to newer ORMs.
π±Maturity & risk
Highly mature and production-ready. At v43 (complete redesign from legacy codebase), 100% test coverage, passing API and E2E CI workflows, active commit history, and 1000s of GitHub stars. The codebase is opinionated and well-structured; the jump to v43 signals confidence in stability despite the major rewrite.
Standard open source risks apply.
Active areas of work
v43 cycle active: new countish and keynav_js paginators, improved configuration automation (reducing setup by 99%), simplified API, and interactive dev tools. Workflows publish docs automatically (.github/workflows/publish-docs.yml), run E2E tests with Puppeteer against real browsers, and manage releases. No open PRs visible in provided data, but active dependabot updates suggest ongoing maintenance.
πGet running
git clone https://github.com/ddnexus/pagy.git
cd pagy
bundle install
bun install # For JS/TS dev dependencies
bundle exec rake # Runs default test suite
bundle exec rspec # API tests
bun run src-lint # Lint JavaScript
Daily commands: Development mode varies by task:
bundle exec pagy-demo # Runs demo app
bundle exec rake pagy:api # API test suite
bun run src-lint # Lint JS/TS
bundle exec rspec --coverage # Full coverage report
IDE: Use .run/*.xml configurations in IntelliJ/RubyMine for one-click test/demo launch.
πΊοΈMap of the codebase
- lib/pagy.rb: Core Pagy class: handles pagination logic, exposes API, loads adapters and frontend integrations
- lib/pagy/paginators/: Contains all paginator strategies (offset, keyset, countish, keynav_js); each is a separate module
- lib/pagy/frontend.rb: Renders pagination navs; framework-agnostic base with ERB templates per framework
- app/pagy/javascripts/: Vanilla JS navigation components: keynav, input_nav_js, series_nav for interactive UI
- .github/workflows/api-test.yml: Defines RSpec test matrix across Ruby versions and adapters
- config/pagy.rb: Default configuration: size, page_param, items_param; guides autodetection logic
- Rakefile: Test and build automation; entry point for bundle exec rake tasks
π οΈHow to make changes
New pagination logic: add lib/pagy/paginators/your_strategy.rb and register in lib/pagy/paginators.rb. New nav: add lib/pagy/frontend/your_framework.rb using the ERB pattern in lib/pagy/frontend/. New JS feature: add app/pagy/javascripts/your_feature.js and export from app/pagy/pagy.js. Tests: add spec/pagy/your_feature_spec.rb. Configuration examples: see config/pagy.rb.
πͺ€Traps & gotchas
- Autodetection requires ORM require: if you load Sequel after Pagy, it auto-detects; load order matters. 2. keynav_js requires JavaScript enabled and a specific URL parameter convention (page_param default is 'page'). 3. countish paginator skips COUNT but requires stable sort keys; will behave oddly on unsorted collections. 4. Frontend nav methods expect framework CSS to be already loaded (e.g., Bootstrap classes in HTML). 5. no explicit .env files: relies on gem loading in Gemfile/Rakefile; no env var injection in tests. 6. TypeScript in src/ is for dev only; published gem is Ruby/JS, not TS.
π‘Concepts to learn
- Keyset Pagination (Cursor-Based) β Pagy's keynav_js and keyset paginators use this to avoid expensive OFFSET queries; critical for understanding performance gains over offset pagination
- Countish Pagination (Approximate Counts) β v43's new countish paginator trades exact row counts for speed; requires understanding trade-offs in UX (estimated totals instead of precise counts)
- ORM Adapter Pattern β Pagy detects and adapts to ActiveRecord, Sequel, Mongoid at runtime; understanding adapters is essential for supporting new ORMs or debugging query behavior
- Frontend Rendering with ERB Partials β Pagy's nav system uses ERB templates per framework (Bootstrap, Bulma); contributors adding new UI frameworks must understand partial rendering and CSS class injection
- Keynav (JavaScript-Based Navigation) β Pagy-exclusive technique combining keyset pagination with AJAX; eliminates page number UI and enables instant navigation; core competitive advantage
- Framework Agnosticism β Pagy core is plain Ruby with opt-in integrations; understanding this separation is key to reusing Pagy in non-Rails contexts (Sinatra, Hanami, APIs)
- TypeScript/JavaScript Interop in Ruby Gems β Pagy ships TS definitions (src/) alongside JS (app/pagy/javascripts/) in a Ruby gem; rare pattern; important for API clarity and IDE support in JS consumers
πRelated repos
kaminari/kaminariβ Direct competitor: Rails pagination gem with scope-based API; Pagy is faster and framework-agnostic but kaminari has more UI presetsmislav/will_paginateβ Legacy pagination gem; Pagy is a modern, zero-dependency alternative with better performancerails/railsβ Required ecosystem: Pagy integrates with ActionController and ActionView for Rails supportjeremyevans/sequelβ Companion ORM: Pagy has first-class Sequel adapter; many users pair Pagy + Sequel for non-Rails projectsddnexus/pagy-cursorβ Official companion gem (if exists) extending keyset pagination; validates Pagy ecosystem maturity
πͺPR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add E2E tests for JavaScript keyset pagination functionality
The repo has .run/Keyset.run.xml and .run/Keyset Sequel.run.xml run configurations, plus an e2e-test.yml workflow, but keyset pagination's JavaScript interactions likely need dedicated E2E coverage. The src/ directory has JavaScript support files that handle pagination UI interactions, and keyset pagination is a distinct feature requiring edge case testing (cursor position, backward navigation, empty states). This would ensure the keyset feature works reliably across browsers.
- [ ] Review existing E2E test patterns in
.github/workflows/e2e-test.yml - [ ] Examine keyset pagination JavaScript in
src/(pagination helpers for cursor handling) - [ ] Create new E2E test file targeting keyset-specific scenarios: cursor edge cases, backward navigation, boundary conditions
- [ ] Integrate new tests into the existing E2E workflow
- [ ] Verify tests pass with
bun runcommands documented in package.json
Add ESLint rules for accessibility in generated nav HTML
The repo generates pagination HTML via assets/nav.html and assets/nav.html.erb templates, and uses ESLint with @stylistic/eslint-plugin and eslint-plugin-promise. However, there's no explicit accessibility linting (no eslint-plugin-jsx-a11y or equivalent for HTML/ERB). Pagination components are critical for accessibility (keyboard navigation, ARIA labels). Adding accessibility-focused ESLint rules would catch regressions early and ensure WCAG compliance.
- [ ] Add
eslint-plugin-jsx-a11yto devDependencies in package.json - [ ] Create
.eslintrcrules for HTML/ERB templates checking for required ARIA attributes (aria-label, aria-current, etc.) - [ ] Add linting script to package.json:
'a11y-lint': 'eslint ./assets/**/*.html.erb' - [ ] Document accessibility expectations in
.github/CONTRIBUTING.md - [ ] Integrate a11y linting into CI workflow (consider extending existing linting steps)
Add TypeScript type definitions for pagy JavaScript API surface
The package.json shows typescript: 6.0.3 and @types/node: 25.6.0 are already included, indicating TypeScript support is in the project's roadmap. However, there are no .d.ts files visible for the JavaScript src/ utilities that consumers of the pagy JS library would use. This would help TypeScript users and provide better IDE autocompletion/documentation. Given the e2e and API test workflows, the JS API is clearly public.
- [ ] Audit JavaScript exports in
src/to identify public APIs (pagination helpers, nav builders, event handlers) - [ ] Create
src/index.d.tswith type definitions for main exports - [ ] Create module-specific
.d.tsfiles matching JavaScript module structure (e.g.,src/utils.d.ts) - [ ] Add TypeScript compilation check to package.json scripts (e.g.,
'type-check': 'tsc --noEmit') - [ ] Update
.github/CONTRIBUTING.mdto document TypeScript expectations for new JS contributions
πΏGood first issues
- Add Pagy::Frontend nav templates for Tailwind CSS (currently only Bootstrap/Bulma/custom in lib/pagy/frontend/). This requires new ERB files and documentation in .github/CONTRIBUTING.md.: easy
- Write integration tests for Pagy + Mongoid in spec/adapters/mongoid_spec.rb; currently only ActiveRecord and Sequel appear in CI workflows. This unblocks Mongoid users.: medium
- Expand E2E test coverage in .github/workflows/e2e-test.yml for keynav_js across multiple browsers using Puppeteer; currently E2E likely only covers basic offset nav. Add tests for edge cases (empty result, single page, large page numbers).: medium
βTop contributors
Click to expand
Top contributors
- @ddnexus β 92 commits
- @jeffse β 2 commits
- @ethancrawford β 1 commits
- @fkmy β 1 commits
- @kelso β 1 commits
πRecent commits
Click to expand
Recent commits
e185ab1β Fix minor typo in keyset docs (#901) (ethancrawford)febc837β Fix broken API Test badge in README.md (#900) (fkmy)18132f6β Fix retype linked files (ddnexus)058d878β Improve Ferrum test stability (ddnexus)42b4a84β Fix broken link (close #897) (ddnexus)5f08538β Merge branch 'dev' (ddnexus)874833cβ Version 43.5.3 (ddnexus)4a0fba2β π Autoload series, a_lambda and page_label (ddnexus)55e0802β Improve Ferrum test stability (ddnexus)d9b37f9β Improve page segment file (ddnexus)
πSecurity observations
The Pagy pagination gem demonstrates a good security posture with automated testing (API and E2E tests), 100% code coverage, and Rubocop compliance. Dependabot is configured for automated dependency monitoring. Primary concerns are the need for regular dependency updates (particularly Puppeteer and TypeScript major versions), verification of community-maintained ESLint plugins, and ensuring any web-facing components have proper security headers configured. No hardcoded secrets, SQL injection risks, or critical misconfigurations were detected in the provided file structure. The project follows security best practices with CI/CD workflows and comprehensive testing.
- Medium Β· Outdated Puppeteer Dependency β
package.json - devDependencies.puppeteer. Puppeteer version 24.42.0 is used for e2e testing. While relatively recent, it should be regularly updated to receive security patches for Chromium vulnerabilities. Consider implementing automated dependency update checks. Fix: Enable Dependabot alerts (already configured in .github/dependabot.yml) and regularly update Puppeteer to the latest stable version. Review security advisories for Chromium. - Medium Β· TypeScript Development Dependency at Major Version 6 β
package.json - devDependencies.typescript. TypeScript 6.0.3 is a major version upgrade. Ensure compatibility with all build tools and conduct thorough testing to verify no breaking changes affect the codebase security or functionality. Fix: Verify TypeScript 6.x compatibility with all integrated tools. Review TypeScript 6.0 release notes for any security-relevant changes. Consider pinning to a specific minor version for stability. - Low Β· ESLint Plugin for Alignment Checks β
package.json - devDependencies.eslint-plugin-align-assignments. The eslint-plugin-align-assignments (v1.1.2) is a community-maintained plugin with limited adoption. Verify its security posture and maintenance status. Fix: Review the plugin's GitHub repository for maintenance status, security issues, and code quality. Consider replacing with officially maintained alternatives if concerns arise. - Low Β· Missing Security Headers Configuration β
Configuration files. The codebase appears to be a Ruby gem for pagination with JavaScript support. No explicit security headers configuration is visible in the provided file structure for any web-facing components. Fix: If the demo application or documentation site handles user input, implement security headers (CSP, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security) in the web server configuration. - Low Β· Broad npm Script Permissions β
package.json - scripts.clean. The npm scripts include commands like 'clean' that execute shell commands (rm -rf). While this is for development only, consider restricting these to prevent accidental data loss. Fix: Document the clean script's destructive nature clearly. Consider adding confirmation prompts for destructive operations. Ensure development team understands the implications.
LLM-derived; treat as a starting point, not a security audit.
πWhere to read next
- Open issues β current backlog
- Recent PRs β what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals β see the live page for receipts. Re-run on a new commit to refresh.