Pull content from outside the content/ directory using [[content_dirs]] in config.toml. This is ideal for documentation that lives alongside source code, or content shared between multiple sites.

Configuration #

Add one or more [[content_dirs]] entries to your config.toml:

[[content_dirs]]
path = "../docs"
url_prefix = "docs"

Fields #

FieldTypeDefaultDescription
pathstringrequiredPath to the external directory (relative to site root)
url_prefixstringrequiredURL prefix for generated pages (e.g. "docs" produces /docs/...)
templatestring"page.html"Template for generated pages
section_templatestring"section.html"Template for generated sections
sort_bystringnoneSort pages: "date" or "title"
rewrite_linksboolfalseRewrite relative .md links to clean URL paths
excludearray of strings[]Files to skip (relative to the external directory)

How it works #

Zorto walks the external directory and converts its files:

  • README.md files become sections (equivalent to _index.md in content/)
  • Other .md files become pages
  • The url_prefix is prepended to all generated URL paths
📂docs/
├── 📝README.mdsection -> /docs/
├── 📂getting-started/
    ├── 📝README.mdsection -> /docs/getting-started/
    ├── 📝installation.mdpage -> /docs/getting-started/installation/
    ├── 📝quick-start.mdpage -> /docs/getting-started/quick-start/
├── 📂reference/
    ├── 📝README.mdsection -> /docs/reference/
    ├── 📝cli.mdpage -> /docs/reference/cli/

External directory structure maps to site URLs.

Title extraction #

Since external markdown files typically lack TOML frontmatter, Zorto extracts:

  • Title from the first # Heading line (or derived from the filename if absent)
  • Description from the first paragraph of prose

The title heading is stripped from the rendered body to avoid duplication.

When rewrite_links = true, Zorto rewrites relative .md links in the external content to clean URL paths that work on the built site:

Original linkRewritten to
[Install](/docs/reference/installation/)[Install](/docs/getting-started/installation/)
[CLI](/docs/reference/cli/)[CLI](/docs/reference/cli/)
[GitHub](https://github.com)unchanged

This allows the same markdown files to work as documentation on both GitHub (where .md links are clickable) and the built site (where clean URLs are used).

Excluding files #

Use exclude to skip specific files. This is useful when you have manual content in content/ that should take precedence:

[[content_dirs]]
path = "../docs"
url_prefix = "docs"
exclude = ["reference/cli.md", "internal/draft.md"]

Excluded files are expected to exist as manually authored content in the content/ directory.

Custom templates #

Assign dedicated templates for external content:

[[content_dirs]]
path = "../docs"
url_prefix = "docs"
template = "docs.html"
section_template = "docs-section.html"
sort_by = "title"

The template field is applied to all pages loaded from this directory. The section_template is applied to all sections (directories with README.md).

Real-world example #

The zorto.dev website uses content_dirs to pull in its own documentation:

# website/config.toml
[[content_dirs]]
path = "../docs"
url_prefix = "docs"
template = "docs.html"
section_template = "docs-section.html"
sort_by = "title"
rewrite_links = true

The docs/ directory lives at the repository root alongside the source code. The website in website/ pulls it in as content under /docs/. This means:

  • Documentation files are readable on GitHub with working relative links
  • The same files render as pages on zorto.dev with clean URLs
  • No content duplication between the repo and the website

Multiple content directories #

You can define multiple [[content_dirs]] entries:

[[content_dirs]]
path = "../docs"
url_prefix = "docs"
rewrite_links = true

[[content_dirs]]
path = "../api-docs"
url_prefix = "api"
template = "api-doc.html"
sort_by = "title"

Each directory is independent with its own URL prefix, templates, and settings.

Further reading #