GitPedia

Pagy

Agnostic pagination in plain ruby

From ddnexusยทUpdated June 19, 2026ยทView on GitHubยท

We needed a leap version to unequivocally signal that it's not just a major version: it's a complete redesign of the legacy code at all levels, usage and API included. The project is written primarily in Ruby, distributed under the MIT License license, first published in 2017. It has gained significant community traction with 4,973 stars and 446 forks on GitHub. Key topics include: bootstrap, bulma, elasticsearch-rails, hanami, jsonapi.

Latest release: 43.5.6โ€” Version 43.5.6

<span>Gem Version</span> <span>
Supported Rubies</span> <span>
API Test</span> <span>
E2E Test</span> <span>
Coverage</span> <span>
Rubocop Status</span> <span>
MIT license</span> <span>
Commits</span> <span>
Downloads</span> <span>
Stars</span> <span>
Gurubase</span>

<h2><img src="assets/images/pagy-the-frog.png" alt="๐Ÿ’š" width="75" style="vertical-align:bottom;"><br/>Pagy the leaping gem!</h2>

Agnostic pagination in plain ruby

<br/> <!-- whats_new_start --> <a href="https://ddnexus.github.io/pagy/sandbox/playground/#demo"> <img src="https://github.com/ddnexus/pagy/raw/dev/assets/images/try-it.svg" width="130"> </a><br><br>

Version 43

We needed a leap version to unequivocally signal that it's not just a major version: it's a complete redesign of the legacy code at all levels, usage and API included.

Why 43? Because it's exactly one step beyond "The answer to the ultimate question of life, the Universe, and everything." ๐Ÿ˜‰

Improvements

This version introduces several enhancements, such as new :countish and :keynav_js paginators and improved automation and configuration processes, reducing setup requirements by 99%. The update also includes a simpler API and new interactive development tools, making it a comprehensive upgrade from previous versions.

  • New :countish Paginator
    • Faster than OFFSET and supporting the full UI
  • New Keynav Pagination
    • The pagy-exclusive technique using the fastest keyset pagination alongside all frontend helpers.
  • New interactive dev-tools
    • New PagyWand to integrate the pagy CSS with your app themes.
    • New Pagy AI available right inside your own app.
  • Intelligent automation
  • Simpler API
    • You solely need the pagy method and the @pagy instance to paginate any collection and use any navigation tag and helper.
    • Methods are autoloaded only if used, and consume no memory otherwise.
    • Methods have narrower scopes and can be overridden without deep knowledge.
  • New documentation
    • Very concise, straightforward, and easy to navigate and understand.

Upgrade to 43

See the Upgrade Guide

<!-- whats_new_end -->

Take a look at the Examples for a quick overview of the new API.

<br/>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> v3 was already quite snappy...

<img src="assets/images/ips-chart.png" title="~40x Faster!" width="500"><br>
<img src="assets/images/memory-chart.png" title="~36x Lighter!" width="500"><br>
<img src="assets/images/objects-chart.png" title="~35x Simpler!" width="500"><br>
<img src="assets/images/resource-consumption-chart.png" title="1,410x More Efficient!" width="500">

<br/>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> Now it's more... with less

  • Compatible with all environments and collection types
  • It can use OFFSET, COUNTISH, COUNTLESS, KEYSET, KEYNAV, SEARCH, CALENDAR, pagination techniques
  • It supports server-side rendering or faster client-side rendering for popular CSS frameworks and APIs
  • It autoloads ONLY the methods that you actually use, with almost zero configuration
  • It boasts 100% test coverage for Ruby, HTML, and JavaScript end-to-end (E2E)
<br/>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> Examples

Pagination code
rb
# Include pagy in your code (usually application_controller.rb) include Pagy::Method # Offset-based pagination @pagy, @records = pagy(:offset, Product.all) # Keyset-based pagination (fastest technique) @pagy, @records = pagy(:keyset, Product.order(my_order).all) # Paginate your collection with one of several paginators @pagy, @records = pagy(...)

See all the available paginators

JSON:API pagination
ruby
# JSON:API nested query string. E.g.: ?page[number]=2&page[size]=100 @pagy, @records = pagy(:offset, Product.all, jsonapi: true) @pagy, @records = pagy(:keyset, Product.order(my_order).all, jsonapi: true) render json: { links: @pagy.urls_hash, data: @records }
JSON-client pagination
ruby
render json: { pagy: @pagy.data_hash, data: @records }
Search server pagination

Available paginators: :elasticsearch_rails, :meilisearch, :searchkick, :typesense_rails

rb
# Extend your models (e.g. application_record.rb) extend Pagy::Search # Paginate with pagy: search = Product.pagy_search(params[:q]) @pagy, @response = pagy(:a_search_paginator, search) # Or get pagy from paginated results: @results = Product.search(params[:q]) @pagy = pagy(:a_search_paginator, @results)
Calendar pagination

Combine time-range and offset pagination.

(Available time units: year, quarter, month, week, and day)

<img src="assets/images/calendar-app.png" width="450"><br/>

ruby
@calendar, @pagy, @records = pagy(:calendar, collection, year: {}, month: {}, offset: {})
ERB
<%== @calendar[:year].series_nav(:bootstrap) %> <%== @calendar[:month].series_nav(:bootstrap) %> <%== @pagy.info_tag %> ... <%== @pagy.series_nav(:bootstrap) %>
Server side rendering
series_nav

Default :pagy, :bootstrap and :bulma styles shown.

<img src="assets/images/pagy-series_nav.png" width="310"><br/>
<img src="assets/images/bootstrap-series_nav.png" width="255"><br/>
<img src="assets/images/bulma-series_nav.png" width="342"><br/>

erb
<!-- Render client side nav bar helpers with different html and styles --> <%== @pagy.series_nav %> <!-- pagy style --> <%== @pagy.series_nav(:bootstrap) %> <%== @pagy.series_nav(:bulma) %>
Client side rendering
rb
# pagy.rb initializer javascript_dir = Rails.root.join('app/javascripts') Pagy.sync_javascript(javascript_dir, 'pagy.mjs') if Rails.env.development?
series_nav_js

Faster and responsive

Dynamically fills the container width.

<img src="assets/images/pagy-series_nav_js-7.png" width="312"><br/>
<img src="assets/images/pagy-series_nav_js-9.png" width="390"><br/>

erb
<!-- Render client side nav bar helpers with different html and styles --> <%== @pagy.series_nav_js %> <!-- pagy style --> <%== @pagy.series_nav_js(:bootstrap) %> <%== @pagy.series_nav_js(:bulma) %>
input_nav_js

Fastest! Combines navigation and info in minimum space.

<img src="assets/images/pagy-input_nav_js.png" width="229"><br/>

erb
<!-- Render client side nav inout helpers with different html and styles --> <%== @pagy.input_nav_js %> <!-- pagy style --> <%== @pagy.input_nav_js(:bootstrap) %> <%== @pagy.input_nav_js(:bulma) %>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> Dev Tools

Integrate pagy with your app's themes interactively (watch demo), and ask specific questions to the Pagy AI right in your app! You need only a single line in your page/layout head to get the Pagy Wand and the Pagy AI:

erb
<%== Pagy.dev_tools %>

<img src="assets/images/dev-tools.png" width="450"><br/>

<a href="https://ddnexus.github.io/pagy/sandbox/playground/#demo"> <img src="https://github.com/ddnexus/pagy/raw/dev/assets/images/try-it.svg" width="130"> </a><br><br>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> Support and Docs

<br/>

Top ๐Ÿ’ฏ Contributors

<!-- top100_start -->

<img src="https://avatars.githubusercontent.com/u/100721?v=4" width="40" title="@ddnexus: 2126 contributions"><img src="https://avatars.githubusercontent.com/u/15097447?v=4" width="40" title="@benkoshy: 83 contributions"><img src="https://avatars.githubusercontent.com/u/11367?v=4" width="40" title="@grosser: 9 contributions"><img src="https://avatars.githubusercontent.com/u/14981592?v=4" width="40" title="@Earlopain: 4 contributions"><img src="https://avatars.githubusercontent.com/u/9843321?v=4" width="40" title="@workgena: 4 contributions"><img src="https://avatars.githubusercontent.com/u/17091381?v=4" width="40" title="@djpremier: 3 contributions"><img src="https://avatars.githubusercontent.com/u/22333?v=4" width="40" title="@bquorning: 3 contributions"><img src="https://avatars.githubusercontent.com/u/235048?v=4" width="40" title="@molfar: 3 contributions"><img src="https://avatars.githubusercontent.com/u/132?v=4" width="40" title="@sunny: 3 contributions"><img src="https://avatars.githubusercontent.com/u/26239269?v=4" width="40" title="@enzinia: 3 contributions"><img src="https://avatars.githubusercontent.com/u/32258?v=4" width="40" title="@espen: 3 contributions"><img src="https://avatars.githubusercontent.com/u/2051199?v=4" width="40" title="@rbngzlv: 2 contributions"><img src="https://avatars.githubusercontent.com/u/8125726?v=4" width="40" title="@simonneutert: 2 contributions"><img src="https://avatars.githubusercontent.com/u/35310?v=4" width="40" title="@kelso: 2 contributions"><img src="https://avatars.githubusercontent.com/u/195636?v=4" width="40" title="@tersor: 2 contributions"><img src="https://avatars.githubusercontent.com/u/1100176?v=4" width="40" title="@thomasklemm: 2 contributions"><img src="https://avatars.githubusercontent.com/u/37790?v=4" width="40" title="@gamafranco: 2 contributions"><img src="https://avatars.githubusercontent.com/u/500826?v=4" width="40" title="@tiagotex: 2 contributions"><img src="https://avatars.githubusercontent.com/u/112558900?v=4" width="40" title="@wimdavies: 2 contributions"><img src="https://avatars.githubusercontent.com/u/29891001?v=4" width="40" title="@jyuvaraj03: 2 contributions"><img src="https://avatars.githubusercontent.com/u/7076736?v=4" width="40" title="@renshuki: 2 contributions"><img src="https://avatars.githubusercontent.com/u/2749593?v=4" width="40" title="@berniechiu: 2 contributions"><img src="https://avatars.githubusercontent.com/u/3427854?v=4" width="40" title="@747: 2 contributions"><img src="https://avatars.githubusercontent.com/u/12479464?v=4" width="40" title="@ashmaroli: 2 contributions"><img src="https://avatars.githubusercontent.com/u/12526288?v=4" width="40" title="@benjaminwols: 2 contributions"><img src="https://avatars.githubusercontent.com/u/67093?v=4" width="40" title="@excid3: 2 contributions"><img src="https://avatars.githubusercontent.com/u/3188392?v=4" width="40" title="@cseelus: 2 contributions"><img src="https://avatars.githubusercontent.com/u/10076?v=4" width="40" title="@claudiob: 2 contributions"><img src="https://avatars.githubusercontent.com/u/50970645?v=4" width="40" title="@sabljak: 2 contributions"><img src="https://avatars.githubusercontent.com/u/4191494?v=4" width="40" title="@jeffse: 2 contributions"><img src="https://avatars.githubusercontent.com/u/421488?v=4" width="40" title="@petergoldstein: 2 contributions"><img src="https://avatars.githubusercontent.com/u/101501?v=4" width="40" title="@rainerborene: 2 contributions"><img src="https://avatars.githubusercontent.com/u/4824537?v=4" width="40" title="@yenshirak: 2 contributions"><img src="https://avatars.githubusercontent.com/u/23448075?v=4" width="40" title="@woller: 1 contribution"><img src="https://avatars.githubusercontent.com/u/43544760?v=4" width="40" title="@WilliamHorel: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1012014?v=4" width="40" title="@okuramasafumi: 1 contribution"><img src="https://avatars.githubusercontent.com/u/12237543?v=4" width="40" title="@olieidel: 1 contribution"><img src="https://avatars.githubusercontent.com/u/211?v=4" width="40" title="@olleolleolle: 1 contribution"><img src="https://avatars.githubusercontent.com/u/43936240?v=4" width="40" title="@PedroAugustoRamalhoDuarte: 1 contribution"><img src="https://avatars.githubusercontent.com/u/2815199?v=4" width="40" title="@pedrocarmona: 1 contribution"><img src="https://avatars.githubusercontent.com/u/891109?v=4" width="40" title="@peter50216: 1 contribution"><img src="https://avatars.githubusercontent.com/u/32079912?v=4" width="40" title="@rafaeelaudibert: 1 contribution"><img src="https://avatars.githubusercontent.com/u/7660738?v=4" width="40" title="@rafaelmontas: 1 contribution"><img src="https://avatars.githubusercontent.com/u/412056?v=4" width="40" title="@rogermarlow: 1 contribution"><img src="https://avatars.githubusercontent.com/u/632682?v=4" width="40" title="@RyanTG: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1478773?v=4" width="40" title="@Tolchi: 1 contribution"><img src="https://avatars.githubusercontent.com/u/310909?v=4" width="40" title="@serghost: 1 contribution"><img src="https://avatars.githubusercontent.com/u/30351533?v=4" width="40" title="@sk8higher: 1 contribution"><img src="https://avatars.githubusercontent.com/u/58137134?v=4" width="40" title="@muhammadnawzad: 1 contribution"><img src="https://avatars.githubusercontent.com/u/69295?v=4" width="40" title="@ronald: 1 contribution"><img src="https://avatars.githubusercontent.com/u/10906059?v=4" width="40" title="@achmiral: 1 contribution"><img src="https://avatars.githubusercontent.com/u/174391530?v=4" width="40" title="@mikepayready: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1038959?v=4" width="40" title="@mcauser: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1393996?v=4" width="40" title="@mauro-ni: 1 contribution"><img src="https://avatars.githubusercontent.com/u/462701?v=4" width="40" title="@borama: 1 contribution"><img src="https://avatars.githubusercontent.com/u/24856?v=4" width="40" title="@creativetags: 1 contribution"><img src="https://avatars.githubusercontent.com/u/24826?v=4" width="40" title="@mcary: 1 contribution"><img src="https://avatars.githubusercontent.com/u/93276?v=4" width="40" title="@marckohlbrugge: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1753398?v=4" width="40" title="@fluser: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6563823?v=4" width="40" title="@maful: 1 contribution"><img src="https://avatars.githubusercontent.com/u/62210?v=4" width="40" title="@geoffreymcgill: 1 contribution"><img src="https://avatars.githubusercontent.com/u/9060346?v=4" width="40" title="@artplan1: 1 contribution"><img src="https://avatars.githubusercontent.com/u/7241024?v=4" width="40" title="@AngelGuerra: 1 contribution"><img src="https://avatars.githubusercontent.com/u/18153165?v=4" width="40" title="@tr4b4nt: 1 contribution"><img src="https://avatars.githubusercontent.com/u/4953187?v=4" width="40" title="@tiejianluo: 1 contribution"><img src="https://avatars.githubusercontent.com/u/28652?v=4" width="40" title="@szTheory: 1 contribution"><img src="https://avatars.githubusercontent.com/u/22420?v=4" width="40" title="@smoothdvd: 1 contribution"><img src="https://avatars.githubusercontent.com/u/87665329?v=4" width="40" title="@rhodes-david: 1 contribution"><img src="https://avatars.githubusercontent.com/u/5484758?v=4" width="40" title="@radinreth: 1 contribution"><img src="https://avatars.githubusercontent.com/u/54139019?v=4" width="40" title="@pranavbabu: 1 contribution"><img src="https://avatars.githubusercontent.com/u/884634?v=4" width="40" title="@okliv: 1 contribution"><img src="https://avatars.githubusercontent.com/u/5013677?v=4" width="40" title="@nedimdz: 1 contribution"><img src="https://avatars.githubusercontent.com/u/468744?v=4" width="40" title="@msdundar: 1 contribution"><img src="https://avatars.githubusercontent.com/u/59817964?v=4" width="40" title="@m-abdurrehman: 1 contribution"><img src="https://avatars.githubusercontent.com/u/10395940?v=4" width="40" title="@ethancrawford: 1 contribution"><img src="https://avatars.githubusercontent.com/u/831536?v=4" width="40" title="@dwieringa: 1 contribution"><img src="https://avatars.githubusercontent.com/u/579103?v=4" width="40" title="@7a6163: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6220668?v=4" width="40" title="@YutoYasunaga: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1322208?v=4" width="40" title="@fkmy: 1 contribution"><img src="https://avatars.githubusercontent.com/u/65494027?v=4" width="40" title="@iamyujinwon: 1 contribution"><img src="https://avatars.githubusercontent.com/u/13119624?v=4" width="40" title="@yhk1038: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6612882?v=4" width="40" title="@ya-s-u: 1 contribution"><img src="https://avatars.githubusercontent.com/u/13472945?v=4" width="40" title="@yshmarov: 1 contribution"><img src="https://avatars.githubusercontent.com/u/9436230?v=4" width="40" title="@Davidzhu001: 1 contribution"><img src="https://avatars.githubusercontent.com/u/190269?v=4" width="40" title="@thattimc: 1 contribution"><img src="https://avatars.githubusercontent.com/u/7021119?v=4" width="40" title="@thomaschauffour: 1 contribution"><img src="https://avatars.githubusercontent.com/u/361323?v=4" width="40" title="@snkashis: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6059188?v=4" width="40" title="@sliminas: 1 contribution"><img src="https://avatars.githubusercontent.com/u/71972054?v=4" width="40" title="@ShyamBorsaniya: 1 contribution"><img src="https://avatars.githubusercontent.com/u/64050?v=4" width="40" title="@gjtorikian: 1 contribution"><img src="https://avatars.githubusercontent.com/u/149513?v=4" width="40" title="@tulak: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6208777?v=4" width="40" title="@Federico-G: 1 contribution"><img src="https://avatars.githubusercontent.com/u/18742365?v=4" width="40" title="@egimenos: 1 contribution"><img src="https://avatars.githubusercontent.com/u/73437?v=4" width="40" title="@elliotlarson: 1 contribution"><img src="https://avatars.githubusercontent.com/u/17459154?v=4" width="40" title="@hungdiep97: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6125?v=4" width="40" title="@Cosmo: 1 contribution"><img src="https://avatars.githubusercontent.com/u/6763624?v=4" width="40" title="@davidwessman: 1 contribution"><img src="https://avatars.githubusercontent.com/u/813150?v=4" width="40" title="@david-a-wheeler: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1169363?v=4" width="40" title="@daniel-rikowski: 1 contribution"><img src="https://avatars.githubusercontent.com/u/1530175?v=4" width="40" title="@thedanbob: 1 contribution">

<!-- top100_end --> <br/>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> Credits

Special thanks to:

  • Ben Koshy for his contributions to the documentation, user support and interaction with external frameworks
  • JetBrains for their free OpenSource license.
  • The Stargazers for showing their support
<br/>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> Repository Info

<details> <summary>How to contribute</summary>

See Contributing

</details> <details> <summary>Versioning</summary> </details> <details> <summary>Branches</summary>
  • The master branch is the latest rubygem-published release. It also contains docs and comment changes that don't affect the published code. It is never force-pushed.
  • The dev branch is the development branch with the new code that will be merged in the next release. It could be force-pushed.
  • Expect any other branch to be internal, experimental, force-pushed, rebased and/or deleted even without merging.
</details> <br/> <br/>

<span style="font-size: .65em; vertical-align: middle">๐Ÿ’š</span> License

MIT

Contributors

Showing top 12 contributors by commit count.

View all contributors on GitHub โ†’

This article is auto-generated from ddnexus/pagy via the GitHub API.Last fetched: 6/21/2026