Templates without content files (like the homepage template)

In a lot of Hugo projects I end up with a decent amount of markdown files in content that are basically empty. But they are needed because Hugo does only generate a page if I have a content file. It looks like this:

└── content
    └── about
    |   └── _index.md  // <- example.com/about/
    └── posts
        ├── happy
        |   └── index.md  // <- example.com/posts/happy/
        └── _index.md  // <- example.com/posts/
└── layouts
    ├── _default
    │   └── baseof.html
    ├── about
    │   ├── index.html // <- DOES NOT WORK, BUT MAYBE IT SHOULD?
    │   └── list.html // <- example.com/about/
    ├── posts
    │   ├── list.html
    │   └── single.html
    └── index.html  // <- example.com/

In the above example, I would just like to have a file in layouts/about/index.html that is constructed together with baseof.html and maybe some partials that are included. For a page that is very unique - like about pages usually are - I can just write everything in HTML and don’t see the point in creating an additional file content/about/_index.md.

Everything should work like the Homepage Template

Wouldn’t it make sense for Hugo to also take template files under layouts that are not list.html or single.html and render them? This would be the exact same behavior as the homepage template’s index.html.

Better Learning Path

Besides avoiding some unnecessary markdown files in the content folder, there is another reason why I’m asking for this feature: it would enable a very easy learning path for developers as they adopt Hugo for their first SSG project.

Let me explain: I teach a lot of web development to people that are new to programming. Our learning path usually goes like this (also see my HTML/CSS tutorials for details):

  1. Learn very basic HTML
  2. Learn very basic CSS
  3. Upload to a simple static hosting like Netlify
  4. Improve HTML/CSS and maybe spice up with some JavaScript

Students can get very far with this. But after a while they will end up with a lot of HTML-pages. And every page, of course, contains a copy of things like <head> and navigation. Students then ask, if there is a better way. And my answer usually is Hugo.

But this step is bigger than it needs to be. If Hugo would allow the above mentioned way to generate layout pages without the need for content files, it would make things much easier.

I could just tell the students: Now, copy everything to the layouts folder. Then use partials and/or baseof.html for the code that is duplicated across multiple. And everything would work and make sense to the students.

Only as a later step I would introduce them to the concept of the content folder and Markdown - probably to show the benefit when having a collection of “things” like blog posts.


What are your thoughts? Do you see a better way to do this or is this a valid feature request for Hugo?

You can define ‘special’ layouts that are neither list.html nor single.html by specifying layout in your front matter.

Your structure, for example, can be made simpler:

content/
├── about.md
└── posts
    └── happy                # or happy.md
        └── index.md
layouts/
├── _default
│   ├── baseof.html
│   ├── list.html
│   ├── single.html
│   └── special.html
└── index.html

with layout: special set on about.md.

That would give you this output:

public
├── about
│   └── index.html          # will use layouts/_default/special.html
├── index.html              # will use layouts/index.html
├── posts
│   ├── happy
│   │   └── index.html      # will use layouts/_default/single.html
│   └── index.html          # will use layouts/_default/list.html
...

docs: https://gohugo.io/templates/lookup-order/

Thanks for your answer but this is not what I’m trying to do. I would like to get rid of the content/about.md (in your case). As in your example: If we have everything in special.html, why do we still need some markdown. Of course, if you place it under layouts/_default it wouldn’t work. But if you placed it in the right folder, Hugo could know where to render it to:

layouts/about/index.html --> should be rendered to --> public/about/index.html

Because: (docs)

Hugo assumes that the same structure that works to organize your source content is used to organize the rendered site.


You are also not limited to markdown content files; you can use html files in content as well. Perhaps that approach is closer to what you want.

As @pointyfar said Hugo also supports pure HTML under /content/.

If that special layout is an one-off and you don’t need to define a layout do it this way.

Yes, that would be another approach. But then we would need to be able to use templating in HTML files inside content, for example to include partials. Otherwise the files are just static (and could thus be placed in static).

Since Hugo 0.52 you can use an Inline Shortcode to call a partial from within a content file:

Also personally as I’ve mentioned yesterday in another thread I use a different technique that can also be used for one-off layouts. From the default single.html template you can do this:

{{ if in (.Permalink | string) "/about/" }}
<-- Unique layout -->
{{ end }}

There are several ways to go about it already. I don’t think there is need for another feature.

1 Like

Thanks, this is helping. I’m fiddling with a solution using shortcodes, but still not completely happy. Here is my current workaround:

Custom Shortcode to include partials

layouts/shortcodes/partial.html (I call it partial to keep it as close to Hugo’s partial syntax - but maybe it’s confusing)

{{ partial (.Get 0) $.Page.Params }}

Using the Shortcode

content/about/index.html

<!DOCTYPE html>
<html lang="en">
<body>
  {{< partial "navigation.html" >}}
  My content
</body>
</html>

For this to work I also need the following layouts/_default/single.html

{{ .Content }}

Alternatives?

That’s as far as I could simplify. Maybe someone sees a solution that is more elegant?

No it doesn’t work quite like that.

Just follow the Example in the Docs (slightly modified) to call the navigation partial that you use site wide from a content file with Inline Shortcodes.

 {{< nav.inline >}}{{ partial "<PATH>/nav.html" . }}{{< /nav.inline >}}