Skip to content
Hextra v0.12 is here! 🎉 Discover what’s new
Organize Files

Organize Files

Directory Structure

By default, Hugo searches for Markdown files in the content directory, and the structure of the directory determines the final output structure of your website. Take this site as an example:

    • _index.md
      • _index.md
      • getting-started.md
        • _index.md
        • organize-files.md
      • _index.md
      • post-1.md

Each of the _index.md files is the index page for the corresponding section. The other Markdown files are regular pages.

content
├── _index.md // <- /
├── docs
│   ├── _index.md // <- /docs/
│   ├── getting-started.md // <- /docs/getting-started/
│   └── guide
│       ├── _index.md // <- /docs/guide/
│       └── organize-files.md // <- /docs/guide/organize-files/
└── blog
    ├── _index.md // <- /blog/
    └── post-1.md // <- /blog/post-1/

Layouts

Hextra offers three layouts for different content types:

LayoutDirectoryFeatures
docscontent/docs/Ideal for structured documentation, same as this section.
blogcontent/blog/For blog postings, with both listing and detailed article views.
defaultAll other directoriesSingle-page article view without sidebar.

To customize a section to mirror the behavior of a built-in layout, specify the desired type in the front matter of the section’s _index.md.

content/my-docs/_index.md
---
title: My Docs
cascade:
  type: docs
---

The above example configuration ensures that the content files inside content/my-docs/ will be treated as documentation (docs type) by default.

Sidebar Navigation

The sidebar navigation is generated automatically based on the content organization alphabetically. To manually configure the sidebar order, we can use the weight parameter in the front matter of the Markdown files.

content/docs/guide/_index.md
---
title: Guide
weight: 2
---

To use a different label in the sidebar than the page’s title, set linkTitle in the front matter. This also affects breadcrumbs (see below).

content/docs/guide/organize-files.md
---
title: Organize Files
linkTitle: Files
---
It is recommended to keep the sidebar not too deep. If you have a lot of content, consider splitting them into multiple sections.

Merge Modes

When using a data-driven sidebar, the merge property controls how children are resolved:

merge: none (default) Only the nodes explicitly listed in items appear. Auto-generated children from the content tree are ignored.

merge: deep Explicit items are rendered first, then any auto-generated children not already listed are appended. This lets you pin important pages at the top while keeping the rest auto-generated.

- link: /docs/guide/
  merge: deep        # auto children are appended
  items:
    - link: /docs/guide/quickstart/   # pinned at top
    - link: /docs/guide/installation/ # pinned second
    # remaining pages under /docs/guide/ are appended automatically

Pages with sidebar.exclude: true in front matter are excluded from both merge modes.

Sort Order

By default, sidebar pages are sorted by weight (which falls back to date when no weight is set). For sections with many pages that should be listed alphabetically, you can switch to sorting by title.

Global configuration in hugo.yaml:

hugo.yaml
params:
  sidebar:
    sort: title

Per-section override in the section’s _index.md front matter:

content/docs/api/_index.md
---
title: API Reference
sidebar:
  sort: title
---

The per-section setting takes precedence over the global configuration. Supported values are weight (default) and title.

Group Headings

Sidebar entries without a link are rendered as non-clickable group headings. This is useful for organizing pages into logical groups without creating a dedicated section page:

data/<lang>/sidebar/docs.yaml
- title: Reference
  icon: book-open
  items:
    - link: /docs/api/
    - link: /docs/cli/

“Reference” will appear as a label in the sidebar with its children listed below. Group headings with children include a collapsible toggle.

This is also a way to expose a folder that has no _index.md: declare a group with the desired title and list its child pages explicitly.

Search Input

Place the search input inline in the sidebar by adding a node with type: search:

data/<lang>/sidebar/docs.yaml
- type: search
- link: /docs/getting-started/
- link: /docs/guide/
  merge: deep

This is useful when the navbar search is disabled or when you want a sticky search at the top of the docs sidebar on desktop.

Scoping by Section

Data-driven sidebars are scoped per section. Place files under data/<lang>/sidebar/ mirroring the content tree; the lookup walks from the deepest matching section upward, so a more specific file wins:

        • docs.yaml
          • sidebar-lab.yaml
        • api.yaml

With the layout above, pages under /docs/sidebar-lab/ use sidebar/docs/sidebar-lab.yaml; other /docs/* pages fall back to sidebar/docs.yaml; pages under /api/* use sidebar/api.yaml. Sections without a matching file fall back to auto-discovery.

Section Navigation

Section Pagination Order

The order in which pages, accessed via PAGE.PrevInSection and PAGE.NextInSection in a page collection, are ordered, is reversed by default.

To disable this reversed ordering you can set the reversePagination custom parameter in the page front matter to false. By default reversePagination is set to true.

Example

Given the following directory structure:

    • _index.md
      • _index.md
        • _index.md
          • index.md
          • index.md
          • index.md

And the following front matter in the posts:

content/blog/my-blog-series/post-a/index.md
---
title: Post A
weight: 1
---
content/blog/my-blog-series/post-b/index.md
---
title: Post B
weight: 2
---
content/blog/my-blog-series/post-c/index.md
---
title: Post C
weight: 3
---

If the reader is at the bottom of post-b/index.md, they will see that the next page is post-a, and the previous page is post-c. This is due to reversePagination being set to true by default. This is ok when we want our posts to be displayed in chronological order from latest to oldest. However, in the case of a blog series where there are multiple parts, we typically want people to read the first post, and then move to the second and so on. So we want to disable the reversed ordering.

We can turn off reversePagination in every blog post in this series by adding the following front matter to my-blog-series/_index.md

content/blog/my-blog-series/_index.md
---
title: My Blog Series
cascade:
    params:
        reversePagination: false
---

We are using cascade here to propagate the setting to all posts in the my-blog-series so that reversePagination is set to false for all descendents. This will now ensure that when the reader is on post-b/index.md they will see that the next page is post-c and the previous page is post-a.

Breadcrumb Navigation

Breadcrumbs are auto-generated based on the directory structure of /content.

For example, consider the file structure demonstrated above. Given that structure, the breadcrumbs atop the page at /docs/guide/organize-files/ would appear automatically as follows:

Documentation > Guide > Organize Files

Customizing Breadcrumb Link Titles

By default, each breadcrumb link is generated based on that page’s title parameter. You can customize this by specifying a linkTitle.

For example, if instead of Organize Files we wanted the breadcrumb to be Foo Bar:

content/docs/guide/organize-files.md
---
linkTitle: Foo Bar
title: Organize Files
---

This would now generate the following breadcrumbs:

Documentation > Guide > Foo Bar

Enabling and Disabling Breadcrumbs

Whether breadcrumbs are enabled, or disabled, by default for a page, is determined by its content type and page kind:

Content TypeSectionPage
docsEnabledEnabled
blogDisabledEnabled
Any other typeDisabledDisabled

You can override these defaults on a page by setting breadcrumbs in its front matter:

content/docs/guide/organize-files.md
---
breadcrumbs: false
title: Organize Files
---

Similarly you can use cascade to override the defaults on a page and its decendents:

content/portfolio/_index.md
---
title: "Portfolio"

cascade:
  params:
    breadcrumbs: true
---

Configure Content Directory

By default, the root content/ directory is used by Hugo to build the site. If you need to use a different directory for content, for example docs/, this can be done by setting the contentDir parameter in the site configuration hugo.yaml.

Add Images

To add images, the easiest way is to put the image files in the same directory as the Markdown file. For example, add an image file image.png alongside the my-page.md file:

      • my-page.md
      • image.png

Then, we can use the following Markdown syntax to add the image to the content:

content/docs/my-page.md
![](image.png)

We can also utilize the page bundles feature of Hugo to organize the image files together with the Markdown file. To achieve that, turn the my-page.md file into a directory my-page and put the content into a file named index.md, and put the image files inside the my-page directory:

        • index.md
        • image.png
content/docs/my-page/index.md
![](image.png)

Alternatively, we can also put the image files in the static directory, which will make the images available for all pages:

      • image.png
      • my-page.md

Note that the image path begins with a slash / and is relative to the static directory:

content/docs/my-page.md
![](/images/image.png)
Last updated on