Filesystem-based Routing
Stati uses filesystem-based routing, which means the structure of your site/ directory directly determines the URLs of your website. This approach is intuitive, predictable, and doesn’t require complex routing configuration.
Basic Routing
Files to URLs
The mapping from files to URLs is straightforward:
site/
├── index.md → /
├── about.md → /about/
├── contact.md → /contact/
└── blog/
├── index.md → /blog/
├── first-post.md → /blog/first-post/
└── second-post.md → /blog/second-post/
Directory Structure
Every directory can have its own index.md file, which becomes the homepage for that section:
site/
├── index.md → / (site homepage)
├── docs/
│ ├── index.md → /docs/ (docs homepage)
│ ├── getting-started.md → /docs/getting-started/
│ └── api/
│ ├── index.md → /docs/api/ (API section homepage)
│ └── reference.md → /docs/api/reference/
URL Generation Rules
Clean URLs
Stati automatically generates clean URLs by:
- Removing the
.mdfile extension - Converting
indexfiles to directory URLs - Adding trailing slashes for consistency
about.md → /about/
blog/index.md → /blog/
blog/my-post.md → /blog/my-post/
Important: No Automatic Slug Transform ation
Stati preserves filenames exactly as written (minus the .md extension). There is NO automatic:
- Lowercase conversion
- Space/underscore to hyphen conversion
- Special character removal
- Slug beautification
This means you must use URL-safe filenames from the start:
✅ Good (URL-safe):
about.md → /about/
my-post.md → /my-post/
getting-started.md → /getting-started/
⚠️ Problematic (not URL-safe):
About.md → /About/ (case-sensitive URL)
my_post.md → /my_post/ (underscore in URL)
my post.md → /my post/ (space in URL - breaks)
post!.md → /post!/ (special chars - problematic)
Filename Best Practices
To ensure clean, working URLs:
- Use lowercase:
about.mdnotAbout.md - Use hyphens for word separation:
my-post.mdnotmy_post.mdormy post.md - Avoid special characters: Use only letters, numbers, and hyphens
- Keep names descriptive but concise:
getting-started.mdnotgetting_started_with_our_platform.md
Nested Routing
Deep Nesting
Stati supports unlimited nesting levels:
site/
└── docs/
└── guides/
└── advanced/
└── customization.md → /docs/guides/advanced/customization/
Section Organization
Organize content by topic, date, or any logical structure:
site/
├── blog/
│ ├── 2024/
│ │ ├── january/
│ │ │ └── new-year-post.md → /blog/2024/january/new-year-post/
│ │ └── february/
│ │ └── valentine-post.md → /blog/2024/february/valentine-post/
│ └── 2023/
│ └── archive/
│ └── old-post.md → /blog/2023/archive/old-post/
Special Files and Directories
Files and Directories Excluded from Routing
Stati excludes certain files and directories from URL generation:
Files and Folders Starting with _ (Underscore)
Critical Rule: Any file or directory starting with _ is excluded from routing:
site/
├── _partials/ ❌ Not routed - Partial templates
│ ├── header.eta
│ ├── footer.eta
│ └── components/
│ └── button.eta
├── _components/ ❌ Not routed - Reusable components
│ └── card.eta
├── _includes/ ❌ Not routed - Include files
│ └── analytics.eta
├── _data/ ❌ Not routed - Data files
│ └── config.json
├── _drafts/ ❌ Not routed - Draft content
│ └── upcoming-post.md
├── partials/ ✅ Routed - Creates /partials/ (no underscore)
│ └── content.md ✅ Routed - Creates /partials/content/
└── published.md ✅ Routed - Creates /published/
Non-Markdown Files
Only .md files become pages. All other file types are automatically excluded:
site/
├── layout.eta ❌ Not routed - Template file (.eta)
├── config.js ❌ Not routed - JavaScript file
├── styles.css ❌ Not routed - Stylesheet
├── image.png ❌ Not routed - Image file
├── .DS_Store ❌ Not routed - Not markdown
├── .gitkeep ❌ Not routed - Not markdown
├── README.md ✅ Routed - Creates /readme/ (is markdown!)
└── index.md ✅ Routed - Creates / homepage
Note: README.md files ARE routed because they are markdown files. If you don’t want a README to appear on your site, either:
- Use a different extension:
README.txt - Place it in an underscore folder:
_docs/README.md - Mark it as draft in front matter:
draft: true
Use Cases for Underscore Exclusion
Partial Templates:
_partials/
├── header.eta # Site header
├── navigation.eta # Main navigation
├── sidebar.eta # Blog sidebar
└── footer.eta # Site footer
Component Library:
_components/
├── button.eta # Reusable button
├── card.eta # Content cards
├── modal.eta # Modal dialogs
└── forms/
├── input.eta # Form inputs
└── validation.eta # Form validation
Data and Configuration:
_data/
├── site-config.json # Site-wide settings
├── navigation.json # Menu structure
├── authors.json # Author information
└── categories.json # Content categories
Development Files:
_drafts/ # Work-in-progress content
_temp/ # Temporary build files
_backup/ # Content backups
_assets/ # Source assets (pre-processing)
This convention allows you to organize helper files, templates, and components without creating unwanted routes, keeping your URL structure clean and intentional.
Layout Files
layout.eta files are special template files that don’t generate routes but define the layout for their directory and subdirectories:
site/
├── layout.eta # Root layout
├── index.md → / (uses root layout)
├── blog/
│ ├── layout.eta # Blog-specific layout
│ ├── index.md → /blog/ (uses blog layout)
│ └── post.md → /blog/post/ (uses blog layout)
Dynamic Content Organization
Date-based Organization
For blogs and news sites, organize by date:
site/
└── blog/
├── index.md
├── 2024/
│ ├── 01/
│ │ ├── 15-new-feature.md → /blog/2024/01/15-new-feature/
│ │ └── 30-update.md → /blog/2024/01/30-update/
│ └── 02/
│ └── 14-valentine.md → /blog/2024/02/14-valentine/
Category-based Organization
For documentation or portfolio sites:
site/
├── projects/
│ ├── web-development/
│ │ ├── ecommerce-site.md → /projects/web-development/ecommerce-site/
│ │ └── portfolio.md → /projects/web-development/portfolio/
│ └── mobile-apps/
│ ├── ios-app.md → /projects/mobile-apps/ios-app/
│ └── react-native.md → /projects/mobile-apps/react-native/
Front Matter URL Override
You can completely override the automatic URL generation using the permalink field in front matter:
---
title: 'Custom URL Example'
permalink: '/custom-path/'
---
# This page will be available at /custom-path/
Important: When using permalink:
- Must be a static string (no template variables or date formatting)
- Must start with
/ - Should end with
/for consistency - Completely replaces the file-path-based URL
Example use cases:
---
# Override deeply nested file path
# File: site/archive/2023/old-posts/article.md
# Without permalink: /archive/2023/old-posts/article/
# With permalink: /featured/article/
permalink: '/featured/article/'
---
---
# Shorten long category paths
# File: site/documentation/api-reference/authentication.md
# Without permalink: /documentation/api-reference/authentication/
# With permalink: /docs/auth/
permalink: '/docs/auth/'
---
Working with the Router
Link Generation
When linking between pages, use absolute paths from the site root:
Check out our [Getting Started page](/getting-started/introduction/) for more information.
Visit the [API documentation](/api/reference/) to learn more.
Navigation Helpers
In templates, you can access routing information:
<nav>
<% if (stati.page.url === '/') { %>
<a href="/" class="active">Home</a>
<% } else { %>
<a href="/">Home</a>
<% } %>
<% if (stati.page.url.startsWith('/blog/')) { %>
<a href="/blog/" class="active">Blog</a>
<% } else { %>
<a href="/blog/">Blog</a>
<% } %>
</nav>
Breadcrumbs
Generate breadcrumbs from the URL structure:
<nav class="breadcrumbs">
<a href="/">Home</a>
<%
const parts = stati.page.url.split('/').filter(Boolean);
let currentPath = '';
%>
<% parts.forEach((part, index) => { %>
<% currentPath += '/' + part; %>
<% if (index < parts.length - 1) { %>
<span class="separator">›</span>
<a href="<%= currentPath %>/" class="breadcrumb-link">
<%= part.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) %>
</a>
<% } else { %>
<span class="separator">›</span>
<span class="current">
<%= part.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) %>
</span>
<% } %>
<% }); %>
</nav>
Best Practices
URL Structure Design
-
Keep URLs short and descriptive
- Good:
/docs/getting-started/ - Avoid:
/documentation/getting-started-with-our-amazing-platform/
- Good:
-
Use consistent naming conventions
- All lowercase
- Hyphens for word separation
- Avoid underscores and special characters
-
Organize by content hierarchy
- Group related content together
- Use logical nesting levels
- Consider your site’s navigation structure
File Organization
-
Use meaningful directory names
site/ ├── getting-started/ # Clear section purpose ├── tutorials/ # Obvious content type └── api-reference/ # Descriptive and specific -
Keep related content together
site/ └── blog/ ├── index.md # Blog homepage ├── layout.eta # Blog-specific layout ├── _partials/ # Blog-specific components └── posts/ # All blog posts -
Use index files for section homepages
- Always provide an
index.mdfor directory sections - Use it to introduce the section and link to subsections
- Make it the navigation hub for that area
- Always provide an
SEO Considerations
-
Descriptive URLs help SEO
/blog/how-to-optimize-website-performance/is better than/blog/post-123/
-
Consistent structure improves crawling
- Use predictable patterns like
/blog/yyyy/mm/post-name/ - Maintain consistent depth levels when possible
- Use predictable patterns like
-
Clean URLs are user-friendly
/contact/is cleaner than/contact.html- Trailing slashes provide consistency
Advanced Routing Patterns
Multi-language Sites
Organize content by language:
site/
├── en/
│ ├── index.md → /en/
│ └── about.md → /en/about/
├── es/
│ ├── index.md → /es/
│ └── acerca.md → /es/acerca/
└── fr/
├── index.md → /fr/
└── apropos.md → /fr/apropos/
API Documentation
Structure API docs logically:
site/
└── api/
├── index.md → /api/ (API overview)
├── authentication.md → /api/authentication/
├── endpoints/
│ ├── users.md → /api/endpoints/users/
│ └── posts.md → /api/endpoints/posts/
└── examples/
├── basic.md → /api/examples/basic/
└── advanced.md → /api/examples/advanced/
Understanding filesystem-based routing is key to organizing your Stati site effectively. Next, learn about Templates & Layouts to understand how your content gets rendered.