RepoPilotOpen in app β†’

ddnexus/pagy

πŸ† The Best Pagination Ruby Gem πŸ₯‡

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained β€” safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI β€” clean foundation to fork and modify.

Learn fromHealthy

Documented and popular β€” useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture β€” runnable as-is.

  • βœ“Last commit 2d ago
  • βœ“8 active contributors
  • βœ“MIT licensed
Show 3 more β†’
  • βœ“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.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/ddnexus/pagy)](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:

  1. 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.
  2. 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.
  3. 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 |

<details> <summary><b>Run all checks</b> β€” paste this script from inside your clone of <code>ddnexus/pagy</code></summary>
#!/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).

</details>

⚑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

  1. 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
  • kaminari/kaminari β€” Direct competitor: Rails pagination gem with scope-based API; Pagy is faster and framework-agnostic but kaminari has more UI presets
  • mislav/will_paginate β€” Legacy pagination gem; Pagy is a modern, zero-dependency alternative with better performance
  • rails/rails β€” Required ecosystem: Pagy integrates with ActionController and ActionView for Rails support
  • jeremyevans/sequel β€” Companion ORM: Pagy has first-class Sequel adapter; many users pair Pagy + Sequel for non-Rails projects
  • ddnexus/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 run commands 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-a11y to devDependencies in package.json
  • [ ] Create .eslintrc rules 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.ts with type definitions for main exports
  • [ ] Create module-specific .d.ts files 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.md to 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

πŸ“Recent commits

Click to expand
  • 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.


Generated by RepoPilot. Verdict based on maintenance signals β€” see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals Β· ddnexus/pagy β€” RepoPilot