Site Configuration

Complete seite.toml reference for your static site: site settings, collections, build options, deployment targets, languages, images, and analytics.

Everything about your seite site is configured in a single seite.toml file. The static site generator uses sensible defaults, so most sections are optional: start with [site] and [[collections]], then add sections as you need them.

Overview

All configuration lives in seite.toml at the project root, created by seite init. Here's a complete example:

[site]
title = "My Site"
description = "A personal blog and documentation"
base_url = "https://example.com"
language = "en"
author = "Jane Doe"

[[collections]]
name = "posts"
paginate = 10

[[collections]]
name = "docs"

[[collections]]
name = "pages"

[build]
output_dir = "dist"
minify = true
fingerprint = true

[deploy]
target = "github-pages"

[languages.es]
title = "Mi Sitio"
description = "Un blog personal"

[images]
widths = [480, 800, 1200]
quality = 80
webp = true
avif = false
lazy_loading = true

[analytics]
provider = "google"
id = "G-XXXXXXXXXX"
cookie_consent = true

[site]

FieldTypeDefaultDescription
titlestringrequiredSite title, used in templates and meta tags
descriptionstring""Site description for SEO
base_urlstring"http://localhost:3000"Full base URL for canonical links, sitemap, RSS
languagestring"en"Default language code
authorstring""Author name for JSON-LD and RSS
Warning

Set base_url to your real domain before deploying. Leaving it as localhost will trigger a pre-flight warning and produce incorrect canonical URLs, sitemaps, and RSS feeds.

[[collections]]

Each [[collections]] entry defines a content collection. See Collections for full details.

[[collections]]
name = "posts"
label = "Blog"
directory = "posts"
url_prefix = "/posts"
default_template = "post.html"
has_date = true
has_rss = true
listed = true
nested = false
paginate = 10
subdomain = "blog"          # optional: deploy to blog.example.com
subdomain_base_url = "https://blog.example.com"  # optional: explicit URL override
deploy_project = "my-blog"  # optional: Cloudflare/Netlify project for subdomain

When subdomain is set on a collection, it gets its own output directory (dist-subdomains/{name}/), its own base URL (https://{subdomain}.{base_domain}), and its own sitemap, RSS, robots.txt, llms.txt, and search index. The collection is excluded from the main site build. Use subdomain_base_url to override the auto-derived URL (useful when base_url contains www). See Collections for details.

[build]

FieldTypeDefaultDescription
output_dirstring"dist"Build output directory
data_dirstring"data"Directory for data files (YAML/JSON/TOML)
public_dirstring"public"Directory for root-level files copied to output without prefix (favicon.ico, .well-known/, _redirects, etc.)
minifyboolfalseStrip CSS/JS comments and collapse whitespace
fingerprintboolfalseAdd content hash to asset filenames for cache busting
mathboolfalseEnable math/LaTeX rendering ($inline$ and $$display$$ blocks via KaTeX)
Tip

Enable minify for production builds. It strips CSS/JS comments and collapses whitespace for smaller files. Enable fingerprint when your CDN caches aggressively: content hashes in filenames ensure browsers always fetch the latest version.

When fingerprint = true, static files get hashed names (e.g., style.a1b2c3d4.css) and an asset-manifest.json is written to the output directory.

CSS processing

seite does not include a Sass/SCSS/PostCSS preprocessor. This is a deliberate design choice: all theme CSS lives inline in the Tera template file, making themes completely self-contained single files with no external dependencies. This means:

  • No build toolchain beyond the seite binary itself
  • Themes are portable: install from a URL, no asset pipeline setup
  • AI-generated themes (seite theme create) produce one complete file

Modern CSS natively supports features that previously required preprocessors: custom properties (variables), nesting, calc(), color-mix(), clamp(). For projects that need Sass, compile externally (sass style.scss static/style.css) and reference the output in your template: seite copies everything in static/ to the output directory.

See Building Custom Themes for more detail on this approach.

Data Files

Place YAML, JSON, or TOML files in the data/ directory to make structured data available in all templates as {{ data.filename }}.

Supported formats

ExtensionFormat
.yaml, .ymlYAML
.jsonJSON
.tomlTOML

Nested directories

Subdirectories create nested keys:

data/
  nav.yaml          → {{ data.nav }}
  authors.json      → {{ data.authors }}
  menus/
    main.yaml       → {{ data.menus.main }}
    footer.yaml     → {{ data.menus.footer }}

Theme integration

All bundled themes conditionally render data.nav for header navigation and data.footer for footer links and copyright. Example data/nav.yaml:

- title: Blog
  url: /posts
- title: About
  url: /about
- title: Docs
  url: /docs

Example data/footer.yaml:

links:
  - title: GitHub
    url: https://github.com/user/repo
  - title: Twitter
    url: https://twitter.com/user
copyright: "2026 My Company"

Conflict detection

The build will error if two data files share the same stem (e.g., authors.yaml and authors.json) or if a file and directory conflict (e.g., nav.yaml and nav/main.yaml). Unknown file extensions are skipped with a warning.

[deploy]

FieldTypeDefaultDescription
targetstring"github-pages"Deploy target: github-pages, cloudflare, netlify
repostringauto-detectedGit repository URL (GitHub Pages)
projectstringauto-detectedProject name (Cloudflare Pages)
auto_commitbooltrueAuto-commit and push before deploying. On non-main branches, auto-uses preview mode

[languages.*]

Optional. Add language sections to enable multi-language support:

[languages.es]
title = "Mi Sitio"
description = "Un blog personal y documentación"

[languages.fr]
title = "Mon Site"

Each language can override title and description. See Multi-language for details.

[images]

Optional. When this section is present, seite automatically processes images in static/. When omitted, images are copied as-is with no resizing or rewriting. New projects created with seite init include this section by default.

FieldTypeDefaultDescription
widthsarray[480, 800, 1200]Target widths in pixels for resized copies
qualityint80JPEG/WebP quality (1-100)
webpbooltrueGenerate WebP variants alongside originals
avifboolfalseGenerate AVIF variants alongside originals (better compression than WebP)
avif_qualityint70AVIF quality (1-100). Lower than WebP is fine — AVIF compresses better
lazy_loadingbooltrueAdd loading="lazy" to <img> tags

When configured, images in static/ are resized to each width, optionally converted to WebP and/or AVIF, and <img> tags in HTML are rewritten with srcset and <picture> elements. AVIF sources appear first in the <picture> element so browsers that support AVIF use it (best compression), falling back to WebP, then the original format. To disable image processing, remove the [images] section entirely.

[analytics]

Optional. When present, analytics scripts are automatically injected into every HTML page during build. Supports Google Analytics 4, Google Tag Manager, Plausible, Fathom, and Umami.

FieldTypeDefaultDescription
providerstringrequiredAnalytics provider: google, gtm, plausible, fathom, umami
idstringrequiredMeasurement/tracking ID (e.g., G-XXXXXXX, GTM-XXXXX, domain, or site ID)
cookie_consentboolfalseShow a cookie consent banner and gate analytics on user acceptance
script_urlstringvariesCustom script URL (required for self-hosted Umami, optional for others)
extensionsarray[]Plausible script extensions (e.g., ["tagged-events", "outbound-links"]). Ignored for other providers and when script_url is set

Examples

Google Analytics 4 (direct):

[analytics]
provider = "google"
id = "G-XXXXXXXXXX"

Google Analytics 4 with cookie consent banner:

[analytics]
provider = "google"
id = "G-XXXXXXXXXX"
cookie_consent = true

Google Tag Manager:

[analytics]
provider = "gtm"
id = "GTM-XXXXXXX"
cookie_consent = true

Plausible Analytics (privacy-friendly, no cookies):

[analytics]
provider = "plausible"
id = "example.com"

For new installations, Plausible now provides a unique snippet per site from your dashboard (Settings → Installation). Use script_url to point to it — features like tagged events, outbound links, and file downloads are toggled in your Plausible site settings and automatically included. seite generates the correct async script tag plus the plausible.init() bootstrapper for custom event support:

[analytics]
provider = "plausible"
id = "example.com"
script_url = "https://plausible.io/js/pa-XXXXXXXXXX.js"

Legacy: Plausible with extensions (pre-October 2025 script)

The old extension-based approach still works for existing setups but won't receive new Plausible features:

[analytics]
provider = "plausible"
id = "example.com"
extensions = ["tagged-events", "outbound-links", "file-downloads"]

The extensions field appends names to the script filename (e.g., script.tagged-events.outbound-links.js). New sites should use script_url with the unique snippet from the Plausible dashboard instead. See the Plausible script update guide.

Fathom Analytics:

[analytics]
provider = "fathom"
id = "ABCDEF"

Self-hosted Umami:

[analytics]
provider = "umami"
id = "abc-def-123"
script_url = "https://stats.example.com/script.js"
Tip

Privacy-respecting analytics like Plausible, Fathom, and Umami don't use cookies. You can typically use them without a consent banner (cookie_consent = false). Google Analytics and GTM set cookies and may require consent under GDPR/ePrivacy: set cookie_consent = true for those.

When cookie_consent = true, a fixed-position banner appears at the bottom of the page on the visitor's first visit. Analytics scripts only load after the visitor clicks "Accept". The choice is stored in localStorage so it persists across visits. The banner is fully accessible with role="dialog", keyboard-navigable buttons, and responsive design.

How it works

Analytics injection happens as a post-processing step after the main build. Every .html file in the output directory is rewritten:

  • Without consent: the analytics <script> tag is injected before </head>. GTM also gets a <noscript> fallback after <body>.
  • With consent: a consent banner with Accept/Decline buttons is injected before </body>. Analytics scripts are loaded dynamically only after the user accepts.

To remove analytics, delete the [analytics] section from seite.toml.

Frontmatter

Content files use YAML frontmatter between --- delimiters:

---
title: "Page Title"
date: 2026-02-18
updated: 2026-02-19
description: "Used in meta tags, OG, Twitter Cards, JSON-LD"
image: /static/preview.jpg
slug: custom-slug
tags:
  - rust
  - web
draft: true
template: custom.html
robots: noindex
extra:
  hero: true
  color: "#4361EE"
---
FieldTypeRequiredDescription
titlestringYesPage title
datedatePosts onlyPublication date (YYYY-MM-DD)
updateddateNoLast modified date
descriptionstringNoSEO description
imagestringNoSocial preview image
slugstringNoOverride auto-generated slug
tagslistNoContent tags
draftboolNoExclude from build unless --drafts
templatestringNoOverride default template
robotsstringNoPer-page robots directive
extramapNoArbitrary data for templates

seite-workspace.toml

For multi-site setups, a seite-workspace.toml at the workspace root configures all sites. Each site still has its own seite.toml.

[workspace]
name = "my-workspace"
shared_data = "data"           # Shared data directory (optional)
shared_static = "static"       # Shared static assets (optional)
shared_templates = "templates" # Shared templates (optional)

[[sites]]
name = "blog"
path = "sites/blog"
# base_url = "https://blog.example.com"  # Override site base_url
# output_dir = "dist/blog"               # Override output location

[[sites]]
name = "docs"
path = "sites/docs"

[cross_site]
unified_sitemap = false    # Combine all sites into one sitemap
cross_site_links = false   # Validate links across sites
unified_search = false     # Combined search index

See Workspaces for the full guide.

Next Steps