How to Add Pagination to a Jekyll Blog
August 09, 2026
If your Jekyll blog only has a handful of posts, displaying every post on one page is perfectly fine.
But as your archive grows, a long list of posts becomes harder to browse.
Pagination solves this by dividing your blog archive into smaller pages — for example, showing six or ten posts per page instead of displaying everything at once.
Jekyll provides pagination through the jekyll-paginate plugin.
1. Install jekyll-paginate
First, add the plugin to your Gemfile:
gem "jekyll-paginate"
Then run:
bundle install
Next, add the plugin to your _config.yml:
plugins:
- jekyll-paginate
paginate: 6
paginate_path: "/blog/page:num/"
Here, paginate: 6 means Jekyll will display a maximum of six posts per page.
The paginate_path setting tells Jekyll where to generate subsequent pages. For example, your archive will look something like:
/blog/
/blog/page2/
/blog/page3/
Jekyll’s official documentation confirms that page 1 is generated at the main blog URL and subsequent pages use the configured pagination path.
2. Make your blog archive an HTML file
There is an important detail with the original jekyll-paginate plugin:
Pagination only works with an HTML index.html page.
It does not work directly from a Markdown page.
So instead of:
blog.md
use:
blog/
└── index.html
For example:
---
layout: default
title: Blog
---
<div class="blog-grid">
{% for post in paginator.posts %}
<article class="post-card">
{% if post.image %}
<img
src="{{ post.image | relative_url }}"
alt="{{ post.title }}"
loading="lazy"
/>
{% endif %}
<h2>
<a href="{{ post.url | relative_url }}"> {{ post.title }} </a>
</h2>
<time datetime="{{ post.date | date_to_xmlschema }}">
{{ post.date | date: "%B %-d, %Y" }}
</time>
<p>{{ post.excerpt | strip_html | truncate: 160 }}</p>
</article>
{% endfor %}
</div>
The important change is:
{% for post in paginator.posts %}
instead of:
{% for post in site.posts %}
paginator.posts contains only the posts belonging to the current page.
3. Add Previous and Next links
Now we can add navigation below the posts:
{% if paginator.total_pages > 1 %}
<nav class="pagination" aria-label="Blog pagination">
{% if paginator.previous_page %}
<a href="{{ paginator.previous_page_path | relative_url }}">
← Newer posts
</a>
{% endif %}
<span>
Page {{ paginator.page }} of {{ paginator.total_pages }}
</span>
{% if paginator.next_page %}
<a href="{{ paginator.next_page_path | relative_url }}">
Older posts →
</a>
{% endif %}
</nav>
{% endif %}
Jekyll provides variables such as previous_page_path, next_page_path, page, and total_pages specifically for building pagination interfaces.
4. Add numbered pages
If you have a larger archive, numbered navigation can be more convenient:
{% if paginator.total_pages > 1 %}
<nav class="pagination" aria-label="Blog pages">
{% if paginator.previous_page %}
<a href="{{ paginator.previous_page_path | relative_url }}">
←
</a>
{% endif %}
{% for page in (1..paginator.total_pages) %}
{% if page == paginator.page %}
<span aria-current="page">
{{ page }}
</span>
{% elsif page == 1 %}
<a href="{{ '/blog/' | relative_url }}">
{{ page }}
</a>
{% else %}
<a href="{{ site.paginate_path | relative_url | replace: ':num', page }}">
{{ page }}
</a>
{% endif %}
{% endfor %}
{% if paginator.next_page %}
<a href="{{ paginator.next_page_path | relative_url }}">
→
</a>
{% endif %}
</nav>
{% endif %}
The special handling for page 1 is important because Jekyll does not generate a /page1/ directory. The first page remains at the main blog URL.
5. Style the pagination
You can keep the CSS simple:
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin: 3rem 0;
}
.pagination a,
.pagination span {
padding: 0.5rem 0.85rem;
text-decoration: none;
}
.pagination a {
border: 1px solid var(--border-color);
}
.pagination span[aria-current="page"] {
font-weight: 700;
}
Since you’re already splitting your SCSS into smaller files, I’d put this into:
assets/css/components/_pagination.scss
and include it from your main style.scss.
How the finished structure might look
For a small Jekyll portfolio like mine, I would keep the blog structure straightforward:
blog/
└── index.html
_posts/
├── 2026-08-18-my-first-post.md
├── 2026-08-24-why-jekyll.md
├── 2026-08-24-modern-web-development.md
└── ...
assets/
└── css/
├── style.scss
└── components/
└── _pagination.scss
With six posts per page, Jekyll will automatically create additional archive pages as your collection grows.
What about jekyll-paginate-v2?
There is also jekyll-paginate-v2, which provides considerably more functionality, including pagination for categories, tags, and collections.
For a simple blog archive, however, the original jekyll-paginate approach is much easier to understand and configure.
If you later want things such as:
- Category pagination
- Tag pagination
- Collection pagination
- More advanced page generation
- More sophisticated pagination controls
then jekyll-paginate-v2 is worth considering.
One limitation to remember
The original jekyll-paginate plugin is intentionally simple. It paginates the overall post collection and does not support filtering pagination by tags or categories.
For example, you can have:
/blog/
with all your posts paginated.
But creating:
/dev-notes/page2/
containing only dev-notes posts requires a more advanced approach.
For my own portfolio, I don’t need that complexity yet.
Keep it simple
For a personal portfolio, I’d start with:
6 posts per page + numbered pagination + Previous/Next links.
That’s enough to keep the archive clean without adding unnecessary complexity.
And the nice thing about Jekyll is that once the pagination is configured, you don’t have to manually create page 2, page 3, page 4, and so on.
Add another post, rebuild the site, and Jekyll handles the archive pages for you.
That’s exactly the kind of automation I like about static-site development.