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]
| Field | Type | Default | Description |
|---|---|---|---|
title | string | required | Site title, used in templates and meta tags |
description | string | "" | Site description for SEO |
base_url | string | "http://localhost:3000" | Full base URL for canonical links, sitemap, RSS |
language | string | "en" | Default language code |
author | string | "" | Author name for JSON-LD and RSS |
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]
| Field | Type | Default | Description |
|---|---|---|---|
output_dir | string | "dist" | Build output directory |
data_dir | string | "data" | Directory for data files (YAML/JSON/TOML) |
public_dir | string | "public" | Directory for root-level files copied to output without prefix (favicon.ico, .well-known/, _redirects, etc.) |
minify | bool | false | Strip CSS/JS comments and collapse whitespace |
fingerprint | bool | false | Add content hash to asset filenames for cache busting |
math | bool | false | Enable math/LaTeX rendering ($inline$ and $$display$$ blocks via KaTeX) |
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
seitebinary 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
| Extension | Format |
|---|---|
.yaml, .yml | YAML |
.json | JSON |
.toml | TOML |
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]
| Field | Type | Default | Description |
|---|---|---|---|
target | string | "github-pages" | Deploy target: github-pages, cloudflare, netlify |
repo | string | auto-detected | Git repository URL (GitHub Pages) |
project | string | auto-detected | Project name (Cloudflare Pages) |
auto_commit | bool | true | Auto-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.
| Field | Type | Default | Description |
|---|---|---|---|
widths | array | [480, 800, 1200] | Target widths in pixels for resized copies |
quality | int | 80 | JPEG/WebP quality (1-100) |
webp | bool | true | Generate WebP variants alongside originals |
avif | bool | false | Generate AVIF variants alongside originals (better compression than WebP) |
avif_quality | int | 70 | AVIF quality (1-100). Lower than WebP is fine — AVIF compresses better |
lazy_loading | bool | true | Add 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.
| Field | Type | Default | Description |
|---|---|---|---|
provider | string | required | Analytics provider: google, gtm, plausible, fathom, umami |
id | string | required | Measurement/tracking ID (e.g., G-XXXXXXX, GTM-XXXXX, domain, or site ID) |
cookie_consent | bool | false | Show a cookie consent banner and gate analytics on user acceptance |
script_url | string | varies | Custom script URL (required for self-hosted Umami, optional for others) |
extensions | array | [] | 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"
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.
Cookie consent banner
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" ---
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Page title |
date | date | Posts only | Publication date (YYYY-MM-DD) |
updated | date | No | Last modified date |
description | string | No | SEO description |
image | string | No | Social preview image |
slug | string | No | Override auto-generated slug |
tags | list | No | Content tags |
draft | bool | No | Exclude from build unless --drafts |
template | string | No | Override default template |
robots | string | No | Per-page robots directive |
extra | map | No | Arbitrary 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
- Collections: configure how posts, docs, and pages behave
- Templates & Themes: use config values and data files in your templates
- Deployment: deploy with the settings you've configured
- Workspaces: manage multiple sites in a single repository