title: How to display Markdown files in nested folders in Next.JS?
body: <p>In my Next.JS project, I have many Markdown files distributed in many folders which are considered as categories. So I have folders called '<em>CategoryOne</em>' and '<em>CategoryTwo</em>' at the root of the project (at the same level as node_modules, pages, public). Each of these folders contains some Markdown files.</p>
  <p>I have a page called <strong>articles</strong> which should render all .md files from '<em>CategoryOne</em>' and '<em>CategoryTwo</em>'. As I have to get them, <strong>articles</strong> is a folder which contains index.js (lists all .md files as articles) and [slug].js (displays the article you clicked).</p>
  <p>Let's take a look! :</p>
  <p><code>pages/articles/index.js</code></p>
  <pre><code>import React, { useState } from 'react'
  import fs from 'fs'
  import path from 'path'
  import matter from 'gray-matter'
  import { useRouter } from 'next/router'
  
  export default function Blog({ posts, postsTwo }) {
      const router = useRouter()
      if (router.isFallback) {
          return &lt;div&gt;Loading...&lt;/div&gt;
      }
      return (
          &lt;&gt;
              {/* Maps articles from both Categories */}
          &lt;/&gt;
      )
  }
  
  export async function getStaticProps() {
      const files = fs.readdirSync(path.join('CategoryOne'))
      const posts = files.map((filename) =&gt; {
          const slug = filename.replace('.md', '')
          const markdownWithMeta = fs.readFileSync(
              path.join('CategoryOne', filename),
              'utf-8'
          )
          const { data: frontmatter } = matter(markdownWithMeta)
  
          return {
              slug,
              frontmatter,
          }
      })
  
      const files2 = fs.readdirSync(path.join('CategoryTwo'))
      const posts2 = files2.map((filename) =&gt; {
          const slug2 = filename.replace('.md', '')
          const markdownWithMeta2 = fs.readFileSync(
              path.join('CategoryTwo', filename),
              'utf-8'
          )
          const { data: frontmatter } = matter(markdownWithMeta2)
  
          return {
              slug2,
              frontmatter,
          }
      })
  
      return {
          props: {
              posts: posts,
              postsTwo: posts2,
          },
      }
  }
  
  </code></pre>
  <p><code>[slug].js</code></p>
  <pre><code>import React, { useState, useEffect } from 'react'
  import fs from 'fs'
  import path from 'path'
  import matter from 'gray-matter'
  import marked from 'marked'
  import { useRouter } from 'next/router'
  
  export default function PostPage({
      frontmatter: { title, date, reading_time, category },
      slug,
      content,
      posts,
  }) {
      
      if (router.isFallback) {
          return &lt;div&gt;Loading...&lt;/div&gt;
      }
  
      return (
          &lt;&gt;
              &lt;div&gt;
                  &lt;h1&gt;{title}&lt;/h1&gt;
                  &lt;p&gt;{date} • {reading_time}&lt;/p&gt;
                  &lt;div&gt;
                      &lt;div dangerouslySetInnerHTML={{__html: marked(content)}}&gt;&lt;/div&gt;
                  &lt;/div&gt;
             &lt;/div&gt;
          &lt;/&gt;
      )
  }
  
  export async function getStaticPaths() {
      const files = fs.readdirSync(path.join('CategoryOne'))
      const paths = files.map((filename) =&gt; ({
          params: {
              slug: filename.replace('.md', ''),
          },
      }))
  
      return {
          paths,
          fallback: false,
      }
  }
  
  export async function getStaticProps({ params: { slug } }) {
      const files = fs.readdirSync(path.join('CategoryOne'))
      const markdownWithMeta = fs.readFileSync(
          path.join('CategoryOne', slug + '.md'),
          'utf-8'
      )
      const { data: frontmatter, content } = matter(markdownWithMeta)
      const posts = files.map((filename) =&gt; {
          const slug = filename.replace('.md', '')
          const markdownWithMeta = fs.readFileSync(
              path.join('CategoryOne', filename),
              'utf-8'
          )
          const { data: frontmatter } = matter(markdownWithMeta)
  
          return {
              slug,
              frontmatter,
          }
      })
      return {
          props: {
              frontmatter,
              slug,
              content,
              posts,
          },
      }
  }
  </code></pre>
  <p>When I click on an article from '<em>CategoryTwo</em>' I got a 404 error. It's because in [slug].js I only could return slug from '<em>CategoryOne</em>'..</p>
  <p>In index.js, getStaticProps() is too long, I would like to get this function recursive. Because I think it would be better if I put the Categories folders into one folder called '<em>posts</em>'. So if there are more categories, I could get all .md files whitout calling them by their names.</p>
  <pre><code>/posts
    |______ /CategoryOne
    |______ /CategoryTwo
  </code></pre>
  <p>To sum up, we have to focus on the getStaticProps(), getStaticPaths() and filesystem libray to recursively list files from subdirectories.</p>
  <p><strong>[EDIT • <em>September 10th 2021</em>]</strong></p>
  <p>I made two functions into my <code>utils/index.js</code>. First one get the subfolders, and the second one dive into each subfolder.</p>
  <pre><code>import { readdir } from 'fs/promises';
  const postsDirectory = path.join(process.cwd(), 'posts');
  
  export function getDirectories(postsDirectory) {
    return fs
      .readdirSync(postsDirectory, { withFileTypes: true })
      .filter((dirent) =&gt; dirent.isDirectory())
      .map((dirent) =&gt; dirent.name);
  }
  
  export async function getAllFiles() {
    const test = getDirectories(postsDirectory);
    let table = [];
    for (const folder of test) {
      const subfolder = path.join(postsDirectory, folder);
      let files = await readdir(subfolder);
      for (const file of files) {
        table.push({ file: file, folder: folder });
      }
    }
    return table;
  }
  
  /* Result
  
  [
    { file: 'markdown-one-1.md', folder: 'CategoryOne' },
    { file: 'markdown-one-2.md', folder: 'CategoryOne' },
    { file: 'markdown-one-1.md', folder: 'CategoryTwo' },
    { file: 'markdown-one-2.md', folder: 'CategoryTwo' },
  ]
  
  */
  </code></pre>
  <p>I found that if you have some subfolders inside your posts folder, you should have the same in your posts pages as the schema below:</p>
  <pre><code>├── node_modules
  ├── package.json
  ├── pages
  │   ├── index.js
  │   ├── _app.js
  │   └── posts
  │       ├── CategoryOne
  │           ├── [id].js //to display .md files of CategoryOne
  │       ├── CategoryTwo
  │           ├── [id].js //to display .md files of CategoryTwo
  ├── ..
  └── posts
      ├── CategoryOne
      │   ├── markdown-one-1.md
      │   ├── markdown-one-2.md
      │   ├── markdown-one-3.md
      │   └── ..
      └── CategoryTwo
          ├── markdown-two-1.md
          ├── markdown-two-2.md
          ├── markdown-two-3.md
          └── ..
  </code></pre>
  <p>There should be a way to automate the creation of those [id].js files depending on how much subfolders you have..</p>