Jekyll Permalinks and URL Structure: The Complete Guide
How Jekyll builds URLs — permalink patterns, built-in styles, custom permalinks for posts, pages, and collections, and best practices for SEO-friendly URLs.
Jekyll gives you precise control over the URL structure of every page on your site. Understanding how permalinks work is important for clean URLs, SEO, and ensuring internal links stay consistent when you reorganise content.
How Jekyll builds URLs by default
By default, Jekyll mirrors your file structure. A file at _posts/2026-08-07-my-post.md generates a URL like /2026/08/07/my-post/. A page at about.md generates /about/.
But the default is rarely what you want for production. The permalink setting in _config.yml (and in individual file front matter) lets you control this precisely.
The permalink setting
Set a global permalink pattern in _config.yml:
permalink: /blog/:title/
This tells Jekyll: every post’s URL should be /blog/ followed by the post’s title-slug.
Built-in permalink styles
Jekyll ships with several named permalink patterns:
permalink: date # /year/month/day/title.html
permalink: pretty # /year/month/day/title/ (trailing slash, no .html)
permalink: ordinal # /year/ordinal/title.html
permalink: weekdate # /year/week/short_day/title/
permalink: none # /title.html
Most sites use pretty or a custom pattern. date (the historical default) produces cluttered URLs. none creates flat URLs with .html extensions.
Permalink placeholders
Build custom patterns using these placeholders:
| Placeholder | Value | Example |
|---|---|---|
:year |
4-digit year | 2026 |
:month |
2-digit month | 08 |
:day |
2-digit day | 07 |
:hour |
2-digit hour (24h) | 14 |
:minute |
2-digit minute | 30 |
:second |
2-digit second | 00 |
:title |
Slugified title | my-post-title |
:slug |
Slug from front matter (fallback to title) | custom-slug |
:categories |
Categories joined by / |
tutorial/jekyll |
:name |
Filename without date and extension | my-post-title |
:path |
Path relative to site root | _posts/my-post.md |
:output_ext |
Output file extension | .html |
Common custom patterns
# Clean blog URL — most common for blog sites
permalink: /blog/:title/
# With date — good for news sites
permalink: /:year/:month/:title/
# Category-based
permalink: /:categories/:title/
# Flat — no nesting
permalink: /:title/
# With date and category
permalink: /:categories/:year/:month/:day/:title/
Recommended permalink for most Jekyll blogs
permalink: /blog/:title/
This gives you:
- Clean, readable URLs:
/blog/jekyll-front-matter-guide/ - No date in the URL (posts stay relevant even when old)
- Consistent
/blog/prefix separating blog content from pages - Easy to remember and share
Avoid including dates in permalinks unless you publish time-sensitive content (news, changelogs) where date context adds value.
Per-page permalink override
Override the global setting in any file’s front matter:
---
layout: page
title: "About"
permalink: /about/
---
---
layout: post
title: "My Special Post"
permalink: /featured/my-special-post/
---
The front matter permalink always wins over the global setting in _config.yml.
Permalinks for pages
Pages (in _pages/ or the root directory) use the same permalink front matter key:
---
layout: page
title: "Browse Themes"
permalink: /themes/
---
---
layout: page
title: "Submit a Theme"
permalink: /submit/
---
Without a permalink, a page at _pages/about.md generates /about (no trailing slash). Set permalink: /about/ explicitly for consistency.
Permalinks for collections
Collections get their permalink pattern in _config.yml under the collection definition:
collections:
themes:
output: true
permalink: /themes/:name/
authors:
output: true
permalink: /authors/:name/
For a file _themes/minimal-mistakes.md, this generates /themes/minimal-mistakes/.
Available placeholders for collections: :name (filename without extension), :path, :output_ext, :title, :categories.
# Custom collection permalink using title from front matter
collections:
themes:
output: true
permalink: /themes/:title/
The :title placeholder in detail
:title uses the post or page title, converted to a URL-safe slug:
- Lowercase
- Spaces replaced with hyphens
- Special characters removed
- Accented characters transliterated (é → e)
Title: "Jekyll Front Matter: The Complete Guide!"
:title → "jekyll-front-matter-the-complete-guide"
If you want a different slug than the auto-generated one, set slug in front matter:
---
title: "Jekyll Front Matter: The Complete Guide!"
slug: jekyll-front-matter-guide
permalink: /blog/:slug/
---
This gives /blog/jekyll-front-matter-guide/ instead of the long auto-generated version.
The :categories placeholder
If posts have categories, :categories generates a nested URL:
---
categories: [Tutorial, Jekyll]
permalink: /:categories/:title/
---
Generates: /tutorial/jekyll/my-post/
If a post has no categories, :categories is omitted from the URL (Jekyll does not include the empty slash).
Warning: Using :categories in your permalink means changing a post’s category changes its URL — which breaks links and SEO. Avoid :categories in permalinks for blog posts. Use it only for intentional category-based URL structures.
Trailing slashes
Jekyll generates index.html inside a folder for trailing-slash URLs:
permalink: /about/
→ _site/about/index.html
→ served at https://example.com/about/
Without a trailing slash:
permalink: /about
→ _site/about.html
→ served at https://example.com/about
Use trailing slashes consistently. Mixing /about/ and /contact causes inconsistency and potential duplicate content. Most modern Jekyll sites use trailing slashes.
Redirect old URLs after changing permalinks
If you change a permalink on an existing post, the old URL breaks. Redirect it using jekyll-redirect-from:
# Gemfile
gem "jekyll-redirect-from"
---
layout: post
title: "My Post"
permalink: /blog/my-new-url/
redirect_from:
- /2026/08/07/my-old-url/
- /blog/my-old-url/
---
Jekyll generates redirect pages at the old URLs pointing to the new one. Essential for maintaining SEO when restructuring content.
Checking generated URLs
To see what URL Jekyll generates for each file, run a build and check the _site/ directory structure — it mirrors your URL structure exactly:
bundle exec jekyll build
find _site -name "index.html" | head -20
Or use jekyll serve and browse to check each URL manually.
Internal linking with the link tag
When linking between pages internally, use the {% link %} or {% post_url %} tag instead of hardcoding URLs — they account for baseurl and raise a build error if the target file does not exist:
<a href="{% link _posts/2026-08-07-my-post.md %}">My Post</a>
<a href="{% post_url 2026-08-07-my-post %}">My Post</a>
Both resolve to the post’s actual URL, whatever the permalink setting.
SEO implications of permalink structure
Keyword in URL: Shorter URLs that include the post’s main keyword perform slightly better. /blog/jekyll-permalinks/ is better than /blog/jekyll-permalinks-and-url-structure-the-complete-guide-2026/.
Avoid dates unless meaningful: /blog/2026/08/07/my-post/ makes content look dated. /blog/my-post/ is evergreen.
Be consistent: Changing URL structure after publishing harms SEO even with redirects. Choose a structure you can live with long-term before publishing.
Use hyphens, not underscores: Google treats hyphens as word separators in URLs. my-post is two words; my_post is one. Use hyphens.
Short is better: The shorter and more descriptive the URL, the better. Remove stop words (the, a, an, and, or) from slugs when they add no meaning.
A complete permalink setup
Here is a solid permalink configuration for a Jekyll blog/marketplace:
# _config.yml
# Blog posts
permalink: /blog/:title/
# Collections
collections:
themes:
output: true
permalink: /themes/:name/
authors:
output: true
permalink: /authors/:name/
Pages set their own permalink in front matter:
# _pages/themes.md
permalink: /themes/
# _pages/about.md
permalink: /about/
# _pages/blog.md (blog index)
permalink: /blog/
This gives a clean, consistent URL structure where /blog/ contains posts, /themes/ contains theme pages, and top-level paths handle static pages.