List blog posts grouped by year with Eleventy
        
        A common request I run into is displaying blog posts grouped by publishing year as I have done in my own blog listing. Here’s how to do it with the static site generator Eleventy. I have published the code as a demo project where you can see how to do both yearly and monthly.
Create a new collection in Eleventy config file
  Eleventy project is configured with
  a configuration file
  that
  can have different names. I’ll refer to this file as
  eleventy.config.js but you can adjust
  accordingly with your own project.
Inside this file, you should have a function like
// ESM
export default async function(eleventyConfig) {
	// Configure Eleventy
};
// or in CommonJS
module.exports = async function(eleventyConfig) {
	// Configure Eleventy
};
Inside this function, we’ll create a new collection that will contain our yearly grouping:
export default async function(eleventyConfig) {
  // Create a new collection that can be accessed in templates
  eleventyConfig.addCollection('byYear', collection => {
	  // Find all Markdown posts in blog folder.
	  // You need to adjust this glob pattern to match your
	  // folder structure.
    const allPosts = collection.getFilteredByGlob('blog/*.md');
    
    // Create an empty object for our new collection
    const byYear = {};
    
    // Go through all original posts
    allPosts.forEach(post => {
      // Assuming there's a date field in front matter for each post,
      // extract the year for the post
      const date = new Date(post.data.date);
      const year = date.getFullYear();
      
      // If current year has not been encoutered yet,
      // create a new entry.
      if(!byYear[year]) {
        byYear[year] = [];
      }
      
      // Add post to the corresponding year
      byYear[year].push(post);
    });
    
    // Our posts are now grouped by year so
    // let's return it as the new collection
    return byYear;
  });
  
  // The rest of your configuration file...
}
  Eleventy is very flexible in how you structure your project and identify your
  blog posts. In the above example, I’m using
  collections.getFilteredByGlob
  which allows you to find all files that match the pattern - in this case, all
  Markdown files from folder blog/.
  Another option is to use
  collections.getFilteredByTag
  which allows you to find all content from your Eleventy project based on a
  tag. For example, if you tag your blog posts as “blog-post”, you can find them
  all with
  collections.getFilteredByTag('blog-post').
Display on blog list
  We can now display these posts in a blog listing page, let’s call it
  blog.njk
{% for year, posts in collections.byYear|dictsort|reverse %}
<h2>{{ year }}</h2>
<ul>
  {% for post in posts | reverse %}
  <li><a href="{post.url}">{{post.data.title}}</a></li>
  {% endfor %}
</ul>
{% endfor %}
  I’m using
  dictsort
  filter to sort the byYear object by key
  and then
  reverse
  it to put the newest on the top. I’m using reverse again for all the posts to
  list them in reverse chronological order too.
Add monthly grouping
  If you blog multiple times a month, you may want to add more granularity and
  list posts by month as well. To do that, let’s adjust the collection creation
  function as (in eleventy.config.js):
eleventyConfig.addCollection('byMonth', collection => {
	  // Find all Markdown posts in blog folder.
	  // You need to adjust this glob pattern to match your
	  // folder structure.
    const allPosts = collection.getFilteredByGlob('blog/*.md');
    
    // Create an empty object for our new collection
    const grouped = {};
    
    // Go through all original posts
    allPosts.forEach(post => {
      // Assuming there's a date field in front matter for each post,
      // extract the year for the post
      const date = new Date(post.data.date);
      const year = date.getFullYear();
      const month = date.getMonth();
      
      // If current year has not been encoutered yet,
      // create a new entry.
      if(!grouped[year]) { grouped[year] = {}; }
      if(!grouped[year][month]) { grouped[year][month] = []; }
      
      // Add post to the corresponding year
      grouped[year][month].push(post);
    });
    
    // Our posts are now grouped by year so
    // let's return it as the new collection
    return grouped;
  });
  
  // I also like to add a filter to turn month numbers into short headings
  eleventyConfig.addFilter('toMonth', month => {
    return ['Jan', 'Feb', 'Mar', 'Apr',
            'May', 'Jun', 'Jul', 'Aug',
            'Sep', 'Oct', 'Nov', 'Dec'][month]
  });
And then in the template:
{% for year, months in collections.byMonth|dictsort|reverse %}
<h2>{{ year }}</h2>
{% for month, posts in months|dictsort|reverse %}
<h3>{{ month|toMonth }}</h3>
<ul>
  {% for post in posts | reverse %}
  <li><a href="{post.url}">{{post.data.title}}</a></li>
  {% endfor %}
</ul>
{% endfor %}
{% endfor %}
            If something above resonated with you, let's start a discussion about it! Email me at juhamattisantala at gmail dot com and share your thoughts. In 2025, I want to have more deeper discussions with people from around the world and I'd love if you'd be part of that.