Skip to navigation Skip to main content
The Equal Justice Initiative
Eleventy
Eleventy Documentation
Stable
2.0.1
Canary
3.0.0-alpha.6
Toggle Menu
Eleventy 5.81s
Nuxt 14.77s

Permalinks

Contents

You can customize the default location of templates to the output directory using Eleventy’s permalinks feature.

Here’s a few examples of how it works by default (assuming your output directory is the default, _site):

Input index.njk
Output _site/index.html
Href /
Input template.njk
Output _site/template/index.html
Href /template/
Input subdir/template.njk
Output _site/subdir/template/index.html
Href /subdir/template/
Input subdir/template/template.njk or subdir/template/index.njk
Output _site/subdir/template/index.html
Href /subdir/template/

Cool URIs don’t change Jump to heading

Eleventy automatically helps you make sure that Cool URIs don’t change.

What to leave out…
File name extension. This is a very common one. "cgi", even ".html" is something which will change. You may not be using HTML for that page in 20 years time, but you might want today's links to it to still be valid. The canonical way of making links to the W3C site doesn't use the extension.

Changing the output location Jump to heading

To remap your template’s output to a different path than the default, use the permalink key in the template’s front matter. If a subdirectory does not exist, it will be created.

Syntax YAML Front Matter
---
permalink: "this-is-a-new-path/subdirectory/testing/index.html"
---

The above is functionally equivalent to:

Syntax YAML Front Matter
---
permalink: "this-is-a-new-path/subdirectory/testing/"
---

Both of the above examples will write to _site/this-is-a-new-path/subdirectory/testing/index.html.

Fear not: if multiple input files attempt to write to the same output location, Eleventy will throw an error for you!

WARNING:
While index.html is optional, it is a Common Pitfall to leave off the trailing slash! If you forget it, the browser may attempt to download the file instead of displaying it (unless you’ve done some extra work to set up your Content-Type headers correctly).

Skip writing to the file system Jump to heading

If you set the permalink value to be false, this will disable writing the file to disk in your output folder. The file will still be processed normally (and present in collections, with its url and outputPath properties set to false) but will not be available in your output directory as a standalone template.

Syntax YAML Front Matter
---
permalink: false
---

You may use data variables here (and template syntax, too). These will be parsed with the current template’s rendering engine. It’s recommended to use the provided slugify filter to create URL-safe strings from data.

For example:

Syntax YAML Front Matter using Liquid, Nunjucks
---
title: This is a New Path
permalink: "subdir/{{ title | slugify }}/index.html"

---

Writes to _site/subdir/this-is-a-new-path/index.html.

INFO:
Using the data cascade you have the power to change the default behavior for permalinks for all content in your project. Learn more about the special page variables useful for permalinks to see examples of this behavior: page.fileSlug and page.filePathStem.
Expand to see another example using Liquid’s date filter.
Syntax YAML Front Matter using Liquid
---
date: "2016-01-01T06:00-06:00"
permalink: "/{{ page.date | date: '%Y/%m/%d' }}/index.html"

---

Writes to _site/2016/01/01/index.html. There are a variety of ways that the page.date variable can be set (using date in your front matter is just one of them). Read more about Content dates.

Put quotes around template syntax in YAML Jump to heading

WARNING:
YAML Pitall: If your permalink uses template syntax, make sure that you use quotes! Without quotes YAML may try to parse this as an object if the first character is a {, for example permalink: {{ page.filePathStem }}.html. This is a common pitfall.
Syntax YAML
permalink: "{{ page.filePathStem }}.html"

The error message might look like can not read a block mapping entry; a multiline key may not be an implicit key.

Custom File Formats Jump to heading

You can change the file extension in the permalink to output to any file type. For example, to generate a JSON search index to be used by popular search libraries:

Syntax EJS
---
permalink: "index.json"
---


<%- JSON.stringify(collections.all) -%>

Advanced Usage Jump to heading

Let's say you have a directory of content templates like recipes/cookies.md and recipes/soup.md and 50 more. Each of these content templates has a title in their frontmatter. While you could manually set a permalink in the frontmatter of each recipe you can also dynamically generate the permalink inside a Directory Data File like recipes.11tydata.js.

Because of the order of the data cascade the title of a content template is not immediately available in the directory data file. However, permalink is a special case of implied Computed Data and will have this data available. Inside of your directory data file recipes.11tydata.js you could write this:

module.exports = {
permalink: function ({ title }) {
return `/recipes/${this.slugify(title)}`;
},
};

The title will be slugified to be URL-friendly.

Mapping one URL to Multiple Files for Internationalization Added in v2.0.0 Jump to heading

Decouple a page’s primary URL from its permalink.

As an example, say you have two content files: about.en.html and about.es.html. You’ve already set up the addGlobalData feature to remap their respective output to _site/about.en.html and _site/about.es.html.

Use server-side redirects to control which of these files is shown.

These will work as expected out of the box, except for the page.url variable and the URL reported in collection objects (et al).

Say we want two or more files on the file system (e.g. about.en.html and about.es.html) to map to a single page URL (/about/—not /about.en.html or /about.es.html). This is now possible using a new URL Transforms feature. URL transforms let you modify the page.url for a content document based.

This example matches any .xx.html URL:

module.exports = function (eleventyConfig) {
eleventyConfig.addUrlTransform(({ url }) => {
// `url` is guaranteed to be a string here even if you’re using `permalink: false`
if (url.match(/\.[a-z]{2}\.html$/i)) {
return url.slice(0, -1 * ".en.html".length) + "/";
}

// Returning undefined skips the url transform.
});
};

This approach unlocks functionality for the default build mode of Eleventy but you could also achieve some of the same functionality using the Edge or Serverless plugins.

Some template syntaxes are nicer than others and you may want to opt-out of the templating engine here. Use the dynamicPermalink option in your front matter to disable this on a per-template basis.

WARNING:
This is a common pitfall for users of the Pug templating engine.
Syntax YAML Front Matter
---
permalink: "/this-will-be-a-string-without-templating/"
dynamicPermalink: false

---

Eleventy includes a global configuration option to disable dynamic templating altogether. This will save a few template renders and is probably marginally faster, too.

Filename .eleventy.js
module.exports = function (eleventyConfig) {
// Enabled by default
eleventyConfig.setDynamicPermalinks(false);
};

Ignore the output directory Jump to heading

To remap your template’s output to a directory independent of the output directory (--output), use permalinkBypassOutputDir: true in your front matter.

Syntax YAML Front Matter
---
permalink: "_includes/index.html"
permalinkBypassOutputDir: true

---

Writes to _includes/index.html even though the output directory is _site. This is useful for writing child templates to the _includes directory for re-use in your other templates.


Other pages in Working with Templates: