Content Organization

How the filesystem maps to your site structure

sukr builds your site structure from your content/ directory. No routing config needed — the filesystem is the config.

The Rule

content/foo/bar.md  →  public/foo/bar.html
content/about.md    →  public/about.html
content/_index.md   →  public/index.html

That's it. Paths mirror exactly, with .md becoming .html.

Directory Layout

content/
├── _index.md           # Homepage (required)
├── _404.md             # → /404.html (custom error page, optional)
├── about.md            # → /about.html
├── contact.md          # → /contact.html
├── blog/               # Section directory
│   ├── _index.md       # → /blog/index.html (section index)
│   ├── first-post.md   # → /blog/first-post.html
│   └── second-post.md  # → /blog/second-post.html
└── projects/
    ├── _index.md       # → /projects/index.html
    └── my-app.md       # → /projects/my-app.html

What Makes a Section

A section is any directory containing _index.md. This file:

  1. Provides metadata for the section (title, description)
  2. Triggers section listing behavior
  3. Appears in the navigation

Directories without _index.md are ignored.

Custom 404 Page

To add a custom "not found" page, create content/_404.md:

+++
title = "Page Not Found"
+++

# Page Not Found

The page you're looking for doesn't exist or has been moved.

[Return to the homepage](/)

sukr renders this to 404.html in the output root. The file is optional — if you don't create _404.md, no 404 page is generated.

Most static hosts (Cloudflare Pages, Netlify, GitHub Pages, Vercel) automatically serve /404.html when a visitor hits an unmatched route. No host-side configuration is needed beyond having the file present.

Draft Mode

Set draft = true in frontmatter to exclude content from the build:

+++
title = "Work in Progress"
draft = true
+++

Drafts are filtered from all output — page rendering, navigation, section listings, feeds, and the sitemap. The file stays in your content directory but produces no HTML. Remove the field (or set draft = false) to publish.

Aliases (Redirects)

Aliases let you redirect old URLs to a page's current location. Set aliases in frontmatter:

+++
title = "New Location"
aliases = ["/old/path", "/another/old/path"]
+++

For each alias, sukr generates an HTML redirect stub using <meta http-equiv="refresh">. Bare paths like /old/path produce /old/path/index.html; paths with extensions like /old/page.html are used as-is.

Section Discovery

sukr automatically discovers sections during the build:

  1. Scans content/ for directories containing _index.md
  2. Collects all .md files in that directory (excluding _index.md)
  3. Renders the section index template with the collected items
  4. Renders individual content pages (for blog-type sections)

The section type determines which template renders the index. It resolves in order:

  1. Frontmatter overridesection_type = "blog" in the section's _index.md
  2. Directory namecontent/blog/ becomes type blog

For the full section type reference (built-in types, frontmatter fields, and template dispatch), see Sections.

Navigation builds automatically from:

  • Top-level .md files (except _index.md) → page links
  • Directories with _index.md → section links

Items sort by weight in frontmatter (lower first), then alphabetically.

+++
title = "Blog"
weight = 10  # Appears before items with weight > 10
+++

Hierarchical Navigation

When nav.nested = true in your config, section children appear as nested sub-items:

Features           ← Section link
  ├─ Templates     ← Child page
  ├─ Sections      ← Child page
  └─ Highlighting  ← Child page
Getting Started    ← Top-level page

Child pages inherit their parent section's position in the nav tree. Within a section, children sort by weight then alphabetically.

Without nested navigation (the default), only top-level items appear in the nav.

URL Examples

Source Path Output Path URL
content/_index.md public/index.html /
content/_404.md public/404.html /404.html
content/about.md public/about.html /about.html
content/blog/_index.md public/blog/index.html /blog/
content/blog/hello.md public/blog/hello.html /blog/hello.html

Key Points

  • No config files for routing
  • Directory names become URL segments
  • _index.md = section index, not a regular page
  • _404.md = custom error page, rendered to 404.html at output root
  • Flat output structure (no nested index.html per page)