Documentation

Last updated in git: 2026-06-11

Markdown site directory structure

A Markdown site in Everlock is a Git repository. Every file you push is either served directly, rendered as a page, or used as site infrastructure. This page explains what each file and directory does, why it exists, and how Everlock treats it.

The rules described here only apply to sites running in markdown mode. In html mode, all files are served as-is and none of this structure is interpreted.


Top-level overview

A minimal but fully functional site might look like this:

my-site/
├── site.toml
├── index.md
├── about.md
├── assets/
│   └── style.css
├── images/
│   └── logo.svg
├── layouts/
│   ├── base.html
│   ├── single.html
│   └── list.html
├── shortcodes/
│   └── callout.html
└── docs/
    ├── _index.md
    ├── getting-started.md
    └── reference.md

More complex sites add data/, format variant templates, and additional section directories.


site.toml — site-wide configuration

site.toml at the root configures global metadata and structural behavior. Everlock reads it on every request; you do not need to restart to see changes.

title = "My Site"
description = "A site served by Everlock"
base_url = "https://example.com"
paginate_by = 12
sitemap = true
ignore_dirs = ["out", "vendor"]

[nav]
links = [
  { label = "Home",  url = "/" },
  { label = "Docs",  url = "/docs/" },
  { label = "About", url = "/about" },
]

[markdown]
syntax_highlighting = true
highlight_style = "InspiredGitHub"

[taxonomies]
category = "categories"
FieldPurpose
titleSite name used in <title> tags and templates
descriptionDefault meta description for all pages
base_urlAbsolute URL base, used for sitemap and RSS
paginate_byItems per page on list pages; omit to disable pagination
sitemapSet to true to serve /sitemap.xml; defaults to false. Requires base_url for correct absolute URLs
nav.linksNavigation items available to templates as site.nav.links
markdown.syntax_highlightingToggle code block syntax highlighting
markdown.highlight_styleName of a Syntect highlight theme
taxonomiesCustom taxonomy fields; each key maps a URL prefix to a frontmatter field
ignore_dirsRoot-relative directories to skip when scanning markdown and serving files; defaults to []

site.toml is internal infrastructure. It is never served over HTTP.

Ignored directories

In markdown mode Everlock automatically skips any path component that starts with a dot (for example .git/, .cursor/, .venv/). Files under those directories never become pages, never appear in section listings, and are not served as static assets.

Use ignore_dirs to extend that filter to non-hidden directories — typical candidates are generated output folders or vendored dependencies you keep in the repo for tooling but do not want published:

ignore_dirs = ["out", "vendor", "generated/cache"]

Entries are root-relative and match a directory and everything beneath it.


index.md — the root page

The file index.md at the root of the repository becomes the page at /. It is the only page that lives at the root without a directory.

index.md  →  /

Example:

---
title: My Site
date: 2026-01-01
---

# Welcome

This is the home page.

If you want a section directory to have its own landing page, use _index.md inside that directory instead (see below).


_index.md — section metadata and landing pages

_index.md is a special file that lives inside a section directory. It is not a regular content page. It provides:

  • a title for the generated section listing
  • optional introductory content displayed above the list of child pages
  • an optional layout override for the section listing template
  • a draft flag to suppress the section
docs/
├── _index.md        ← section metadata
├── getting-started.md
└── reference.md

When you visit /docs/, Everlock:

  1. reads docs/_index.md for the section title and intro
  2. lists all child .md files in docs/ as a generated page index
  3. uses the layout: from _index.md (or falls back to list.html)
  4. never exposes _index itself as a link in the listing

Example _index.md:

---
title: Documentation
layout: blog_list
---

The full reference for running and extending Everlock.

Without a _index.md, the section title defaults to the URL path and no intro text is shown. The listing still works.

Choosing a section layout

By default, section listings use list.html. To use a different template, set layout: in _index.md:

---
title: Project updates
layout: blog_list
---

This tells Everlock to render the /updates/ listing with layouts/blog_list.html instead of layouts/list.html. The blog_list.html template receives the same page, pages, and pagination context variables as list.html.


Regular content pages

Any .md file that is not index.md or _index.md becomes a content page at a URL derived from its path:

about.md              →  /about
docs/reference.md     →  /docs/reference
updates/2026-01-15-release.md  →  /updates/2026-01-15-release

Subdirectories become URL segments automatically. You do not need to register routes.

Frontmatter

Every page can have a YAML frontmatter block at the top:

---
title: My page title
date: 2026-01-15
tags: [guide, setup]
categories: reference
draft: false
layout: article
description: A short description for search and meta tags.
series:
  - getting-started-series
my_custom_key: some value
---

Page content starts here.
FieldMeaning
titlePage title shown in <title>, headings, and listings
datePublication date; used for sorting and RSS
tagsList of tags; powers /tags/ routes automatically
draft: trueHides the page from listings, search, RSS, and direct access
layoutTemplate name (without .html) inside layouts/; defaults to single.html
descriptionPer-page meta description; falls back to site.toml description
seriesList of series names this page belongs to; enables prev/next navigation

Any key not in the set above becomes an extra field available to templates as page.extra.your_key.

Any key whose value is a YAML list of strings becomes available as page.extra_lists.your_key. This is how series and custom taxonomies work.

Draft pages

Setting draft: true excludes the page from all generated output: it will not appear in listings, the search index, RSS, sitemaps, or tag pages. It is also not accessible over HTTP directly.

---
title: Work in progress
draft: true
---

Content here is invisible until draft is removed.

<!--more--> — the read-more split

Placing the HTML comment <!--more--> inside page content splits the page into a visible summary and the rest of the article. The content before <!--more--> becomes the page summary available to templates and is used in listing cards.

---
title: My article
---

This paragraph is the summary. It appears in listing views.

<!--more-->

This paragraph and everything after it only appears on the full page.

layouts/ — templates

The layouts/ directory holds Tera templates that control how pages are rendered. Every file in layouts/ is registered as a template, using its path relative to layouts/ as the name. The file extension is the output format — .html for web pages, .vcf for vCards, .json for JSON, etc.

layouts/
├── base.html      ← outer shell: <html>, <head>, <body>, nav, footer
├── single.html    ← individual content pages
├── list.html      ← section listings and tag pages
├── search.html    ← the /search page
├── blog_list.html ← example: a custom blog-style section listing
├── person.html    ← example: HTML layout for a contact page
└── person.vcf     ← example: vCard format variant for the same page

layouts/ and its contents are never served over HTTP.

base.html

The outer HTML shell. All other templates typically {% extends "base.html" %} and fill in a {% block main %} block. base.html has access to site and page context variables.

single.html

Used for individual content pages. Receives:

VariableContent
page.titlePage title from frontmatter
page.contentRendered HTML of the page body
page.tagsList of tag strings
page.dateFrontmatter date
page.git_dateDate of last git commit for this file
page.summaryRendered HTML of content before <!--more-->
page.relatedUp to 5 pages sharing tags with this page
page.prev_pagePrevious page in the same series, if any
page.next_pageNext page in the same series, if any
page.extraMap of scalar extra frontmatter fields
siteParsed site.toml

list.html

Used for section listings, tag pages, and taxonomy pages. Receives:

VariableContent
page.titleSection title (from _index.md or path)
page.contentRendered HTML from _index.md body
pagesList of child page objects, each with title, url, tags, date, git_date
paginationPagination object (only present when paginate_by is set)
siteParsed site.toml

A custom section listing template such as blog_list.html receives exactly the same variables and can be selected via layout: in _index.md.

Format variants

A format variant lets a single Markdown file be served in multiple content types. The page declares a layout: in its frontmatter; Everlock uses that name as the template family and the requested file extension to pick the right template.

---
title: Alice Example
layout: person
---

With this frontmatter:

  • /contacts/alice renders layouts/person.html → HTML page
  • /contacts/alice.vcf renders layouts/person.vcf → vCard
  • /contacts/alice.json renders layouts/person.json → JSON

layouts/person.vcf would look like plain vCard text using Tera syntax:

BEGIN:VCARD
VERSION:3.0
FN:{{ page.title }}
EMAIL:{{ page.extra.email }}
END:VCARD

Supported output content types: json, xml, vcf, atom, txt, csv, ical, ics.


shortcodes/ — reusable content components

The shortcodes/ directory holds Tera template snippets that can be called from inside Markdown content using the `

` syntax. They let you embed structured HTML without writing it directly in your Markdown.

shortcodes/ is never served over HTTP.

Built-in shortcodes

Two shortcodes are available without any template files:

mermaid — diagrams


flowchart LR
A --> B --> C
Optional caption

Renders a Mermaid diagram. You can also load diagram source from a file in the repository:


flowchart TD
  Error[Missing Mermaid source: diagrams/architecture.mmd]
System overview

Mermaid is rendered in the browser via the Mermaid JavaScript library, which Everlock injects automatically when the page uses this shortcode.

link — internal links





Renders a plain link path. Useful for building links programmatically inside templates.

Custom shortcodes

Any file in shortcodes/ becomes a callable shortcode. The template receives an args object with the named parameters you pass.

Example: shortcodes/callout.html

<aside class="callout callout-{{ args.kind | default(value='note') }}">
  {% if args.title %}<strong>{{ args.title }}</strong>{% endif %}
  <div>{{ args.text }}</div>
</aside>

Called in Markdown as:







assets/ — static files

The assets/ directory holds static files like CSS, JavaScript, and fonts. These are served as-is under the /assets/ URL prefix.

assets/
├── style.css     →  /assets/style.css
└── search.js     →  /assets/search.js

There is nothing special about the name assets/. Any directory that contains files without a .md extension will have those files served directly. assets/ is simply the conventional name.


images/ — image files

Images and other media live in images/ by convention and are served directly:

images/
├── logo.svg      →  /images/logo.svg
└── hero.png      →  /images/hero.png

Reference them in Markdown like any regular path:

![Everlock logo](/images/logo.svg)

data/ — structured data for templates

The data/ directory holds .toml files that are loaded and made available to all templates as the data context variable.

data/
├── team.toml
└── releases.toml

data/team.toml:

[[members]]
name = "Alice"
role = "Maintainer"

[[members]]
name = "Bob"
role = "Contributor"

In any template:

{% for member in data.team.members %}
<li>{{ member.name }} — {{ member.role }}</li>
{% endfor %}

Only top-level .toml files in data/ are loaded. Subdirectories are ignored. data/ is never served over HTTP.


Auto-generated routes

Everlock generates several routes automatically for every Markdown site. These do not need any files in the repository.

RouteContent
/index.xmlRSS feed of all pages, sorted by date
/sitemap.xmlXML sitemap of all pages with last-modified dates (only when sitemap = true in site.toml)
/searchSearch page (requires layouts/search.html)
/search-index.jsonJSON search index consumed by the search page
/tags/Tag listing page
/tags/<tag>Pages matching a specific tag

Custom taxonomy routes are also generated automatically based on site.toml:

[taxonomies]
category = "categories"

This generates /category/ and /category/<value> routes for any page with a categories: frontmatter field.


Internal paths — never served

These paths are reserved for site infrastructure. Requests to them return 404 regardless of what exists in the repository:

PathPurpose
site.tomlSite configuration
layouts/HTML templates
shortcodes/Shortcode templates
data/Data files for templates

Series — prev/next navigation

Pages can be linked into an ordered series using the series: frontmatter list. All pages sharing the same series name are sorted by date ascending, and each page gets prev_page and next_page context variables pointing to its neighbors.

---
title: Part 1 — Installation
date: 2026-01-01
series:
  - setup-guide
---
---
title: Part 2 — Configuration
date: 2026-01-08
series:
  - setup-guide
---

In single.html:

{% if page.prev_page %}
<a href="{{ page.prev_page.url }}">← {{ page.prev_page.title }}</a>
{% endif %}
{% if page.next_page %}
<a href="{{ page.next_url }}">{{ page.next_page.title }} →</a>
{% endif %}

Related pages

Every page automatically gets a related list in its template context. Everlock finds up to five other pages that share tags with the current page, ranked by the number of tags in common. No configuration is needed; it follows from your tag usage.

{% if related %}
<aside>
  <h3>Related</h3>
  <ul>
    {% for p in related %}
    <li><a href="{{ p.url }}">{{ p.title }}</a></li>
    {% endfor %}
  </ul>
</aside>
{% endif %}

Full example: a blog

Here is a concrete repository layout for a simple blog, with annotations showing what Everlock does with each file:

my-blog/
├── site.toml                     ← site config, nav, pagination
├── index.md                      ← serves /
├── about.md                      ← serves /about
├── assets/
│   └── style.css                 ← serves /assets/style.css
├── images/
│   └── avatar.jpg                ← serves /images/avatar.jpg
├── layouts/
│   ├── base.html                 ← shared HTML shell
│   ├── single.html               ← article pages
│   ├── list.html                 ← default section listing
│   └── blog_list.html            ← date-first post index
├── shortcodes/
│   └── callout.html              ← 



 shortcode
└── posts/
    ├── _index.md                 ← title: "Posts", layout: blog_list
    ├── 2026-01-10-hello.md       ← serves /posts/2026-01-10-hello
    └── 2026-02-04-followup.md    ← serves /posts/2026-02-04-followup

Visiting /posts/ renders a blog-style index using blog_list.html, with each post listed by date and title. The _index.md controls the section heading and which template is used. Each post file is a regular content page served by single.html.


Read next

sites markdown reference structure