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 Markdown content files.
- Explicit Sections: Directories containing
_index.mdare treated as explicit sections. The_index.mdfile provides metadata (title, description), controls custom listing layouts, and displays in the navigation menus. - Virtual Sections: If a subdirectory does not contain
_index.mdbut contains other Markdown files,sukrautomatically instantiates a virtual section for it. This virtual section uses default frontmatter settings, deriving its title from the directory name.
This recursive section discovery allows building deeply nested content hierarchies without the need to define boilerplate _index.md files at every intermediate level.
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.
Relative URL Prefixes¶
When organizing content in deep directory structures, linking to pages or assets at the root of the site (e.g., /style.css or /images/logo.png) can be error-prone when served from subdirectories.
To simplify referencing assets and links relative to the site root, sukr supports the . (or .) placeholder directly in your Markdown content body. At build time, sukr automatically replaces this placeholder with the correct relative prefix (such as ., ../, or ../../) matching the depth of the current page.
For example, a Markdown file located at content/blog/first-post.md can reference root-relative links and images like so:
[Return to Home](./index.html)

During build time, this gets resolved to:
[Return to Home](../index.html)

Section Discovery¶
sukr automatically discovers sections during the build:
- Scans
content/for directories containing_index.md - Collects all
.mdfiles in that directory (excluding_index.md) - Renders the section index template with the collected items
- Renders individual content pages (for blog-type sections)
The section type determines which template renders the index. It resolves in order:
- Frontmatter override —
section_type = "blog"in the section's_index.md - Directory name —
content/blog/becomes typeblog
For the full section type reference (built-in types, frontmatter fields, and template dispatch), see Sections.
Navigation Generation¶
Navigation builds automatically from:
- Top-level
.mdfiles (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 to404.htmlat output root- Flat output structure (no nested
index.htmlper page)