Working with Collections

Eleventy uses collections to group posts ac­cord­ing to var­i­ous cri­te­ria. A col­lec­tion might con­sist of ar­ti­cles in a se­ries. An­other col­lec­tion could be of posts about books. A third could be all the posts in a par­tic­u­lar di­rec­tory.

Eleventy gives you two ways to cre­ate col­lec­tions:

Tag-based collections

Pages that share a tag are in the same col­lec­tion. A tem­plate with the fol­low­ing front mat­ter would gen­er­ate pages in the col­lec­tions books and reviews.

---
title: Finding Oz
category: Culture
tags:
- books
- reviews
---
. . .

Within a tem­plate col­lec­tions are ac­cessed by name as prop­er­ties of the global collections ob­ject.

<p>
  The title of this page is:
  {{ collections.books[0].data.title }}
</p>

Collections are usu­ally used in loops to it­er­ate over each item in the col­lec­tion.

{% for post in collections.books %}
  {{ post.data.title }}
  {{ post.url }}
  {{ post.data.category }}
  {{ post.data.tags }}
  {{ post.date }}
{% endfor %}

The collections ob­ject it­self looks like this:

{
  "all": [...],
  "nav": [...],
  "books": [
    {
      "inputPath": "./src/articles/finding-oz.md",
      "outputPath": "_site/articles/finding-oz/index.html",
      "fileSlug": "finding-oz",
      "data": {...},
      "date": "2009-08-07T13:52:12.000Z",
      "url": "/articles/finding-oz/",
      "templateContent": "<p>As with most books ... much about The Wizard of Oz</li>\n</ul>\n",
      "template": {...}
    },
    ...
  ],
  "programming": [...],
}

Each prop­erty is an ar­ray of col­lec­tion item ob­jects (the doc also calls them tem­plate ob­jects). The spe­cial col­lec­tion all is an ar­ray of all of the page ob­jects that Eleventy gen­er­ates.

collection item properties
Property Description
inputPath Path to this file including the input directory.
./src/articles/finding-oz.md
outputPath Path to the rendered file.
articles/finding-oz/index.html
fileSlug Short name from the file name. There are rules.
finding-oz
data Data from the front matter of the rendered page. The global variables available to each page.
date The date of this file in UTC. There are rules.
2009-08-07T13:52:12.000Z
url Path to this content. Doesn’t include protocol or host.
/articles/finding-oz/
templateContent The rendered content, not including any layout wrappers.
<p>As with most books … much about The Wizard of Oz</p>
template All sorts of data parsed out of the template. Things like the Eleventy configuration, markdown engine setup, and lots of stuff we probably shouldn’t rely on.
Implementation: How a tag becomes a collection

Custom Collections

In ad­di­tion to the col­lec­tions built from tags, you can use addCollection() in your .eleventy.js con­fig­u­ra­tion file to cre­ate your own col­lec­tions.

For ex­am­ple, this is how to cre­ate a col­lec­tion called articles made up of pages gen­er­ated from tem­plates in the di­rec­tory src/articles/:

eleventyConfig.addCollection("articles",
  collection => collection
    .getAllSorted()
    .filter(item => item.url
                 && ! item.inputPath.includes('index.njk')
                 && item.inputPath.startsWith('./src/articles/')))

addCollection() takes two ar­gu­ments:1

You might think that the collection pa­ra­me­ter is an ar­ray of tem­plate ob­jects like the tag-based collections ob­ject. In­stead, this pa­ra­me­ter is an in­stance of a TemplateCollection, which is de­rived from Sortable, and looks like this:

{
  "items": [
    { ... },
    . . .
    { ... }
  ],
  "sortFunctionStringMap": { ... },
  "sortAscending": true,
  "sortNumeric": false
}

Its items prop­erty is an ar­ray of all the tem­plate ob­jects. It’s the same as collections.all. You don’t want to ac­cess the items di­rectly like this: collection.item[n]. Instead use the fol­low­ing meth­ods to get the items.

collection api methods
Method Description
getAll() Gets all of the items in arbitrary order.
getAllSorted() Gets all of the items in order.
getFilteredByTag(tagName) Get all of the items with a specific tag.
getFilteredByGlob(glob) Gets all of the items whose inputPath matches one or more glob patterns.

The items are al­most the same as the ones in the tag-based col­lec­tions. In tag-based col­lec­tions, items have templateContent. In addCollection() col­lec­tions, items have _pages. I don’t know why.

You can use addCollection() to cre­ate col­lec­tions of pages. Since Eleventy 0.5.3, you can use it to cre­ate col­lec­tions or ar­bi­trary ob­jects.

For in­stance, this is how you’d make a col­lec­tion that con­sists of an ar­ray of all the cat­e­gory prop­er­ties:

module.exports = function(collection) {
  let catSet = new Set()

  collection.getAllSorted().forEach(item =>
        typeof item.data.category === "string"
    &&  catSet.add(item.data.category))

  return [...catSet]
};

Implementation: How custom collections get built
  1. addCollection() does­n’t ac­tu­ally do any­thing other than to as­so­ci­ate the col­lec­tion-build­ing func­tion with the col­lec­tion name. The col­lec­tion-build­ing func­tion it­self is called later in getUserConfigCollectionsData().

    addCollection(name, callback) {
      name = this.getNamespacedName(name);
    
      if (this.collections[name]) {
        throw new UserConfigError(
          `config.addCollection(${name}) already exists. Try a different name for your collection.`
        );
      }
    
      this.collections[name] = callback;
    }
    
    ↩︎