Jekyll Pagination That Scales: Built-in Paginate vs Manual Limit Offset
Jekyll pagination splits into two patterns: the jekyll-paginate gem for the posts index and manual Liquid limit/offset for custom collections. Choose per page size and URL structure to balance build time and URL stability.
14 Nov 2025, 21:39 UTC

Your Jekyll build starts taking minutes and the archive pages at /page/2/ return 404 after an upgrade. The useful takeaway is that pagination in Jekyll is not one feature: the built-in paginate gem handles the posts index only, and custom collections or performance tuning require manual Liquid limit and offset. Pick the strategy that matches the collection and hosting budget.
The concrete problem with medium-traffic blogs
With a few hundred posts, the default Jekyll setup that renders all posts on the home page balloons memory use during build. Splitting the index into numbered pages reduces per-page render cost, but the way you split matters for build time, URL stability, and what you can paginate.
Jekyll 4.0 removed the core paginate tag. Pagination now requires an explicit gem. If you upgrade without adding the gem, the paginate variable is undefined and no /page/2/ files are generated. Permalink changes can also break existing archive URLs if the server does not rewrite /page/2/ to the generated path.
Built-in pagination for the posts index
The jekyll-paginate gem provides paginate and paginate_path in _config.yml and a paginator object in index.html. It only works for the default posts collection and a single index page.
A minimal configuration for a posts blog is:
# Gemfile
gem 'jekyll-paginate'
# _config.yml
paginate: 12
paginate_path: "/page/:num/"
With this, Jekyll generates index.html and /page/2/, /page/3/, etc. Each page receives a paginator object with posts, page, per_page, and total_pages.
Where to verify. Run jekyll build from the project root with write permission to the _site directory. Inspect _site/page/2/ for an index.html file containing the expected number of posts per page. Run bundle list | grep jekyll in the project root to confirm the jekyll-paginate gem is active. Risk: adding the gem changes the build dependency; on shared hosting you must ensure Ruby and Bundler are available at build time.
Manual pagination with Liquid limit and offset
For custom collections like portfolio or documentation, the paginate gem does not apply. Liquid limit and offset filters let you slice a collection manually.
limit keeps only the first N items, offset skips the first N items. Together they simulate pages without a gem.
{% assign per_page = 10 %}
{% assign page_num = page.num | default: 1 | minus: 1 %}
{% assign offset = page_num | times: per_page %}
{% assign items = site.portfolio | sort: 'date' | reverse %}
{% assign page_items = items | slice: offset, per_page %}
This approach requires you to create a page per number yourself, for example portfolio/2/index.md with front matter num: 2. It gives finer control over URL structure and collection choice, at the cost of manual page creation and maintenance.
Performance trade-off and limitation
Build cost scales with posts per page and total pages. Keeping per_page low reduces per-page render work but increases the number of generated pages and the size of the paginator data. On shared hosting, exceeding roughly 50 posts per page can noticeably increase build time and memory usage.
Limitations to plan for:
- jekyll-paginate only paginates the posts index. It cannot paginate custom collections.
- Changing paginate_path after launch breaks existing /page/2/ URLs unless you add server rewrites or redirects.
- Manual limit/offset pagination does not provide previous/next links automatically; you must build them.
A practical check is to compare build times before and after changing paginate. Run jekyll build with a clean _site directory and note the duration. Inspect the generated page count under _site/page/.
Actionable close
Use jekyll-paginate with a conservative per_page value for the main blog index and lock paginate_path early. For collections, decide if manual limit/offset pages are worth the maintenance overhead versus accepting a single long page. Verify gem activation and generated output after any change, and preserve old archive URLs with redirects if you modify the pagination path.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.