Skip to main content
Common Features:

Fast Pagination with Pagy


Episode 261 · September 6, 2018

Pagy is 29x faster at pagination in their benchmarks which makes it an ultra fast and lightweight pagination library

Views Pagination


Fast Pagination with Pagy

This episode we are diving into a relatively new pagination gem called pagy. It adds pagination links to the bottom of the page. You might be familiar with using kaminari or will paginate in the past, but the reason i wanted to talk about pagy is because of these benchmarks.


It claims that atleast in the benchmarks that they used, which i hope are fairly real world.


29 times faster than kaminari and 11 times faster than will paginate

Memory Usage

Uses 18 times less memory than kaminari and 7x less memory than will paginate

These are huge improvements both for will paginate and kaminari. So this makes pagy a pretty interesting library.


The way it works is pretty different from the way you might be used to in setting up will paginate and kaminari. Its a bit of a diversion, and you wil need to read the Docs or watch the screencast to set it up because it does not add methods to for example your ActiveRecord relations like you might be used to.

So in this episode we are going to dive into using this as an example but pagy comes with some extensions that you can add to suit your needs. Some of the extensions are

  • array
  • searchkick

This makes pagy more modular because you can then load the extensions you need and not have to get a bunch of extensions you don't need, which will reduce the complexity that your app will be requiring.


Lets create a brand new rails app

rails new -m template.rb pagynation

This creates a scaffold for us so that we can have some models to actually paginage, and then we can setup pagy to do the pagination for us. Then we have to include pagy for the frontend and the backend in different places, which makes the setup slightly different. So pagy is more manual to add into your rails app unlike kaminari and will paginate, because it is build to used in any rack based application.

So we open up our Gemfile and

# Gemfile
gem "pagy"

and then run

bundle install


Then we can proceed to adding the pagy to the backend of our application, and if its something you are going to use in several controllers, you can then add it in application controller or alternatively you can add to the controllers where you will need it.

# application_controller.rb
class ApplicationController < ActionController::Base
  include Pagy::Backend #--- line 1

  ### other code left out

Line 1 above provides the pagy method which we can then use in our scaffolds, to get the number of items we desire.
So lets create a scaffold
rails g scaffold BlogPost title body:text and then rails db:migrate, and then we run the server rails s

# blog_posts_controller.rb
class BlogPostsController < ApplicationController
  before_action :set_blog_post, only: [:show, :edit, :update, :destroy]

  def index 
    #instead of @blog_posts = BlogPost.all --- line 1

    @pagy, @blog_posts = pagy(BlogPost.all) # line 2

    # normally @blog_posts = BlogPost.all.paginate(params) or --- line 3

In line 2 when we do our query, it setups the @pagy object which will keep track of the pagination stuff for us. In line 2, the pagy method does all that is done in line 3 for us, setting up the params and retrieving a specific number of items for us automatically so we don't have to worry about that, and you can configure how many items you want to be retrieved in each query. Pagy stays generic and does all that without interacting with ActiveRecord


Now we have to go into our helpers and include the pagy helpers for our frontend views.

# application_helper.rb 
module ApplicationHelper
  include Pagy::Frontend
  # other code

This makes sure the pagy helpers in the view are available.

Now we can open up


# at the bottom of the file add, which setups our navigation pages for us.
<%= pagy_nav(@pagy) >

When we check this out on the page, we see a bunch of raw html, because of the way this works, but because we trust it safe,we have to then render as html. change <%= pagy_nav(@pagy) > to <%== pagy_nav(@pagy) > or <%= raw pagy_nav(@pagy) > or <%= pagy_nav(@pagy).html_safe >

Now we can clearly see our navigation links, but we have no records so we cannot really navigate, but if we add some records.

In rails console run.

  50.times do |n| 
    BlogPost.create title: "Test Post #{n}"

And if we go back and refresh our page, we now have links that are clickable, and navigate to our pages, and thats it. But if you want to use it with say bootstrap for example you have to add some extra extensions.

Adding Bootrap extension for use with boostrap

So to add an extension we create a configuration file in config/initializers/pagy.rb

# in config/initializers/pagy.rb
require "pagy/extras/bootstrap"

And by adding this, we can now return to our index.html.erb file and instead of using the pagy_nav helper, we can use the bootstrap version which is pagy_nav_bootstrap.
Hence we go from <%== pagy_nav(@pagy) > to <%== pagy_nav_bootstrap(@pagy) > which re-renders our application but with bootstrap styling.

If we observe the logs we see its not rendering any partials, but its instead writing a very fast helper that outputs that for us and its really quick that way. However you can actually call a partial if you want instead by following the Docs which offer several ways by which we can customize the navigation links.

For example we can go to the compact version, which is very useful if you have many navigation pages and want an easy to use interface for the use to select the page they want. You can change
<%== pagy_nav_bootstrap(@pagy) > to <%== pagy_nav_compact_bootstrap(@pagy) >
And you can go even further to render your own version of this and then you go from
<%== pagy_nav_compact_bootstrap(@pagy) > to <%== render "pagy/nav_bootstrap", locals: { pagy: @pagy } >
and you can then write out your own navigation links to suit your specific needs.

Number of items you want to see


# blog_posts_controller.rb
class BlogPostsController < ApplicationController
  before_action :set_blog_post, only: [:show, :edit, :update, :destroy]

  def index 
    #instead of @blog_posts = BlogPost.all --- line 1

    @pagy, @blog_posts = pagy(BlogPost.all, items: 10) # line 2

    # normally @blog_posts = BlogPost.all.paginate(params) or --- line 3

In line 2, we simply pass in the number of items we want to see.


There is room to add some javascript so that you can manipulat the navigation links as the size of the screen changes, to suit your needs which you can find out in the docs.


Pagy is pretty great, it does alot of stuff, and its a little bit new, so there is a little bit may be of unclear moments as you read the instructions, and there is just alot more that you have to setup manually, but you can tweak it to your hearts content to make your navigation for pages work exactly like how you want it which is great. That's it for this episode and i'll talk to you in the next one peace....


Subscribe to the newsletter

Join 18,000+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.