Railsのページネーション入門|PagyとKaminariの使い分けを実例で(速度40倍の理由)

RailsのページネーションgemのPagyとKaminariの比較表。Pagyは速度約40倍・メモリ約36分の1・最新v43系で活発、Kaminariは安定版1.2.2でビュー作り込みと日本語情報が強み。
  • このエントリーをはてなブックマークに追加

スポンサーリンク

一覧ページの表示が重い、記事やユーザーが増えてきて「全部を一気に出すのはさすがにマズい」——そんなときに入れるのがページネーション(ページ分割)です。Railsだと Pagy と Kaminari の2択でまず迷うのではありませんか?

「どっちを入れればいいの?」「Pagyが速いって聞くけど、どれくらい違うの?」という疑問に、この記事で先にケリをつけます。結論の使い分け → 比較表 → それぞれの最小実装 → つまずき対処、の順で、実務でgemを選ぶときの判断軸をまるごと渡します。読み終わる頃には、あなたのプロジェクトでどちらを入れるか迷わなくなるはずです。

まず結論:どっちを使えばいい?

細かい比較は後半でしますが、先に判断の軸だけ渡しておきます。

こんなプロジェクトおすすめ
新規/速度とメモリ重視/依存を薄くしたい/一覧が多くて重いPagy
すでに Kaminari で動いている/ビューヘルパーの手厚さ・情報量を取りたいKaminari
とにかく1つ選べと言われたらPagy(軽量・高速・後述の理由)

ひとことで言えば、「迷ったら Pagy、すでに Kaminari なら無理に乗り換えない」です。新規で入れるなら、速度・メモリ・依存の薄さで Pagy が有利です。一方、既存アプリがすでに Kaminari で回っているなら、動いているものはそのままで十分です。

RailsのページネーションgemのPagyとKaminariの比較表。Pagyは速度約40倍・メモリ約36分の1・最新v43系で活発、Kaminariは安定版1.2.2でビュー作り込みと日本語情報が強み。
Pagyは軽量・高速、Kaminariは手厚い定番。新規ならPagy、既存Kaminariは据え置きが基本

PagyとKaminariの違いを比較表で整理する

2つの違いは「軽さ・速さ」と「手厚さ・情報量」のトレードオフだと捉えると分かりやすいです。主要な違いをまとめました。

観点PagyKaminari
速度(公式ベンチ)約40倍速い基準
メモリ(公式ベンチ)約1/36基準
設計件数と現在ページだけを持つ軽量設計モデルに page / per スコープを生やす
依存ほぼ無し(プレーンなRuby)Railsエンジンとして統合
ビューヘルパー必要十分(HTMLは素なのでCSSを当てる)手厚い(テンプレを生成してカスタム可)
メンテ状況活発(2026年も更新。最新は v43系)安定だが更新は緩やか(安定版 1.2.2)
Rails 8 対応◯◯
情報量・実績増加中長年の実績・日本語情報が豊富

速度・メモリの数値は Pagy 公式が公開しているベンチマーク(同じナビゲーションを同じ件数で描画したときの比較)に基づくものです。あくまで公式の計測条件での値なので絶対視は禁物ですが、「Pagyのほうがかなり軽い」という傾向はどのベンチでも共通しています。

なぜPagyは速くて軽いのか

数字だけ見ると「なんでそんなに差が出るの?」と思いますよね。理由はシンプルで、2つのgemが「ページネーションのために何を持つか」がまったく違うからです。

なぜPagyが軽いかを示す図。Kaminariはページごとの情報をオブジェクトで多く抱えるのに対し、Pagyは全体件数と現在ページの2つの数字だけを持ちリンクを計算で組み立てるため軽量。
Kaminariは多くのオブジェクトを抱える/Pagyは数字2つ。リンクが多い画面ほど差が開く

Kaminari はモデルに page / per というスコープを生やし、ページごとの情報をActiveRecord寄りの仕組みで扱います。手軽で分かりやすい反面、そのぶん生成されるオブジェクトが多くなります。

対して Pagy が保持するのは、基本的に「全体の件数」と「今何ページ目か」だけです。ページ番号のリンク(1, 2, 3 … 次へ)は、この2つの数字から計算して組み立てます。余計なオブジェクトを作らないので、メモリも処理時間も小さく済む、というわけです。とくにページ番号のリンクが多い(20ページ分並ぶような)画面ほど、この差は開いていきます。

Pagyの最小実装(Pagy 43)

ではPagyを実際に入れてみましょう。ここでは2026年時点の最新である Pagy 43系の書き方で進めます。まずはGemfileに追加して bundle install するだけ。初期設定ファイル(イニシャライザ)は必須ではありません。

# Gemfile
gem 'pagy'

次に、コントローラで Pagy::Method を include し、一覧を取得している箇所を pagy 経由に書き換えます。1ページあたりの件数は limit: で指定します。

class PostsController < ApplicationController
  include Pagy::Method

  def index
    # @posts = Post.all  ← これを↓に置き換える
    @pagy, @posts = pagy(:offset, Post.all, limit: 20)
  end
end

ポイントは、pagy が「ページ情報を持つ @pagy」と「そのページ分のレコード @posts」の2つを返すところです。あとはビューで、レコードを普通に表示しつつ、ページ番号のナビゲーションを1行足すだけです。

<% @posts.each do |post| %>
  <%= render post %>
<% end %>

<%== @pagy.series_nav %>

series_nav が「1, 2, 3 … 次へ」のリンクを出力してくれます。出力されるHTMLは素の状態なので、見た目はCSSやTailwindで整える前提です(このあたりはTailwind CSSの使い方の記事も参考にどうぞ)。

古いPagy(v9以前)を使っている場合の注意

ネット上の記事や既存プロジェクトでは、まだ古いPagyの書き方を見かけることが多いです。Pagyは v43 で書き方が大きく変わったので、以下のような記述を見たら「古い版だな」と判断してください。

やること古い書き方(v9以前)新しい書き方(v43)
コントローラのincludeinclude Pagy::Backendinclude Pagy::Method
ヘルパーのincludeinclude Pagy::Frontend不要
ページ取得pagy(Post.all, limit: 20)pagy(:offset, Post.all, limit: 20)
ビューのナビpagy_nav(@pagy)@pagy.series_nav

すでに古いPagyで動いているアプリを、無理に最新へ上げる必要はありません。ただ、これから新規で入れるなら最新の書き方に合わせておくと、公式ドキュメントとも食い違わずに済みます。

Kaminariの最小実装

次はKaminari。長年Railsで使われてきた定番で、日本語の情報も豊富です。こちらもGemfileに追加して bundle install します。

# Gemfile
gem 'kaminari'

Kaminariは、モデルに生えた page / per スコープを呼ぶだけ。include などの準備は不要です。1ページあたりの件数は per で指定します。

class PostsController < ApplicationController
  def index
    @posts = Post.page(params[:page]).per(20)
  end
end

ビューでは paginate ヘルパーを1行置くだけでナビゲーションが出ます。

<% @posts.each do |post| %>
  <%= render post %>
<% end %>

<%= paginate @posts %>

見た目を細かく作り込みたいときは rails g kaminari:views default でテンプレートを生成し、直接編集できます。「ページャのHTMLを自分のプロジェクトに置いて、がっつりカスタムしたい」ケースではKaminariの手厚さが効いてきます。

なお、Kaminariの安定版は 1.2.2 で、リリースの更新ペースは緩やかです。Rails 8でも動作しますが、「今も活発に開発が続いているgemがいい」という基準なら Pagy に分があります。

つまずきポイント逆引き

導入時によくハマるところを、原因と対処でまとめておきます。

症状原因と対処
Pagyで undefined method 'pagy'コントローラの include Pagy::Method を書き忘れ。共通化したいなら ApplicationController に置く
Pagyのナビが「ただのリンク」で崩れる出力HTMLは素の状態。CSS/Tailwindで見た目を当てる。Bootstrap等の枠も series_nav(:bootstrap) で選べる
Kaminariで2ページ目に飛べないpage(params[:page]) を渡し忘れ。page(1) のように固定していないか確認
件数の多いテーブルでページ表示自体が重い総件数の COUNT が重い。件数を出さない方式(Pagyなら件数レスの paginator)に切り替える手もある

ページネーション+includesでN+1も一緒に潰す

一覧ページが重い原因は、実は「件数の多さ」より N+1クエリ のことが多いです。ページネーションで「1ページ分だけ」に絞ったうえで、関連データを includes でまとめて引くと、表示は一気に軽くなります。

# Pagyの場合
@pagy, @posts = pagy(:offset, Post.includes(:user, :tags), limit: 20)

# Kaminariの場合
@posts = Post.includes(:user, :tags).page(params[:page]).per(20)

「ページで件数を絞る」×「includes で関連をまとめて引く」は、一覧高速化の王道の組み合わせです。rails ブログ機能の実装方法7選のような記事一覧UIでも、この2つをセットで入れておくと安心です。アバター画像を表示する一覧のように、行ごとに関連レコードや画像を出す画面では特に効果が分かりやすいです。

ケース別のおすすめ

「で、自分の場合は?」に答えるために、よくあるケースで整理します。

Pagyが向くケース

  • 新規アプリで、これからページネーションを入れる
  • 一覧が多い・件数が多く、速度とメモリを重視したい
  • 依存gemを増やしたくない・軽い構成を保ちたい
  • APIのJSONレスポンスにもページ情報を載せたい(軽量なので相性が良い)

Kaminariが向くケース

  • すでにKaminariで動いていて、乗り換える理由が特にない
  • ページャのHTMLをテンプレートとして生成し、がっつり作り込みたい
  • チームにKaminariの知見があり、日本語情報を頼りたい

迷ったときのひとことルールは、「新規なら Pagy、既存の Kaminari は据え置き」。動いている認証やページネーションはそれ自体が資産なので、速さのためだけに慌てて乗り換える必要はありません。技術の選定に迷ったときの調べ方はエンジニアの仕事は「知っていること」より「調べられること」もどうぞ。

まとめ

Railsのページネーションgem、PagyとKaminariの使い分けを最後に整理します。

  • Pagy:件数と現在ページだけを持つ軽量設計で、公式ベンチでは約40倍速い・メモリ約1/36。新規ならまずこちら。最新の v43 は include Pagy::Method → pagy(:offset, ...) → @pagy.series_nav
  • Kaminari:page / per で直感的、ビューの作り込みが得意で日本語情報も豊富。安定版 1.2.2 でRails 8でも動く
  • 数値はPagyやKaminari公式ベンチが根拠。傾向として「Pagyが軽い」は共通
  • 判断軸は「新規なら Pagy、既存の Kaminari は無理に乗り換えない」。ページネーション+includes で一覧はさらに軽くなる

一覧が重いと感じたら、まずはページネーションと includes の合わせ技から。新規プロジェクトなら、この機会に gem 'pagy' を入れて series_nav を1行足すところから始めてみてはいかがでしょうか。

スポンサーリンク

  • このエントリーをはてなブックマークに追加