Configuration

epresso is configured with a TOML file, site.toml, validated by Pydantic at load time. Missing file → sensible defaults. Every build/dev/check run loads site.toml from the project root.

Load order

  1. site.toml — base configuration.
  2. site.<env>.toml (when --env <name> or EPRESSO_ENV is set) — deep-merged over site.toml (per-environment URL, toggles, API keys, …).

See [Environment variables](environment-variables.md for the full environment story.

Top-level structure

  
toml
[site]name = "My Site"url = "https://example.com"language = "en"description = ""repository = "" # source repo URL for "view source / edit this page" links # (unset → derived from the git origin remote)branch = "main" # branch those source/edit links point at # (unset → the repo's HEAD branch)docs_source = "" # set when previewing docs from a path (`epresso docs --theme`)[build]output = "dist" # output dir (default dist)content = "content" # collection data dirpages = "pages" # routes dirlayouts = "layouts" # default layout dircomponents = "components"styles = "styles" # global stylesheet dirassets = "assets"static = "public" # files copied verbatim to the output roottrailing_slash = "always" # always | never | ignoreclean_urls = truecompress_html = false # minify HTML (skips <pre>/<script>/<style>)redirects = true # emit redirect pages from the `redirects` config[markdown]highlight = true # Pygments syntax highlighting for fenced codeadd_slug_ids = trueautolink_headings = truetoc_heading = "" # reserved: declared but not implemented — nothing reads it yetdefault_layout = "" # layout for direct Markdown pages that set none of their owncode_component = "" # component to render fenced code blocks through, server-sidecode_components = {} # per-language overrides, e.g. { tree = "Tree" }extensions = [] # extra markdown-it featurescomponents = [] # custom component tags to resolve inside markdown[assets]hash = truecss = ["css/main.css"] # buildable CSS entry pointsjs = ["js/app.js"] # buildable JS entry points[content] # optional draft/private page visibilityshow_drafts = false # hide `draft: true` entries in productionshow_private = false # hide `_`-prefixed (private) entries in production# Unset (omit) to keep the default: shown in development/preview, hidden in# production. Set explicitly here and override in site.<env>.toml for dev/prod.[seo]sitemap = truerobots = true[seo.llms] # llms.txt (https://llmstxt.org/)enabled = truepath = "/llms.txt"title = "" # defaults to the site namedescription = "" # defaults to the site description[seo.rss] # RSS/Atom feedenabled = falsecollection = "" # content collection to build the feed frompath = "/rss.xml"title = "" # defaults to the site namedescription = "" # defaults to the site descriptionlimit = 0 # 0 = all entriesurl_template = "/{collection}/{id}/" # URL for each item[search]enabled = falseindex = "search-index.json"# When enabled, a core BM-25 search index (no external JS) is written to the# output at build time. The docs theme consumes it client-side.[dev]toolbar = { enabled = true, placement = "bottom" } # dev-only overlay; placement: bottom | top[[docs]] # build a docs section into the site (repeat for several)source = "docs" # Markdown dir, or a project dir with its own site.tomlbase = "/docs/" # public sub-path within the sitetheme = "" # theme for bare Markdown (default: the bundled docs theme)out = "" # output subdir of dist/ (default: derived from base)plugins = ["mypkg:MyPlugin"] # dotted-path plugin specs[layers]use = [ # extra component/layout roots, layered under the site's own "./vendor/components", # a directory path "pkg:epresso_ui", # an installed Python package "github:owner/epresso-components@v1", # a repo (tarball, cached in .cache/layers/)]

Redirects

Redirects are configured as [[redirects]] tables. Target may be a string (permanent 301) or { destination, status } for 302:

  
toml
[[redirects]]"/old-home/" = "/"[[redirects]]"/legacy/" = { destination = "/new/", status = 302 }

Each emits a browser-safe meta-refresh page under dist/<from>/index.html and participates in incremental builds. Set [build] redirects = false to disable. Invalid targets (missing destination) are rejected at load time.

Directory layout

The build.* keys let you rename the convention directories. There are helper accessors on the loaded config: dir_content(), dir_pages(), dir_layouts(), dir_components(), dir_styles(), dir_assets(), dir_static(), dir_output(), and cache_dir() (the incremental cache, gitignored).

All of these are resolved against source_root()<root>/src when that directory exists, <root> otherwise (Astro/Nuxt-style, no config needed). dir_static() (public/), dir_output() (dist/) and cache_dir() (.cache/) always stay at the project root, as do site.toml and content.config.py. Content collection base paths are resolved against the same source root. See Project structure.

External component/layout roots come from [layers] use — see Layers.

Programmatic loading

  
python
from epresso.config import load_configconfig = load_config(root=".", env="production")print(config.site.url, config.dir_output())

SEO: canonical URLs

Set the site's absolute origin in site.toml:

  
toml
[site]url = "https://example.com"

epresso does not auto-emit a canonical tag. Add one in your layout <head> so each page points at its canonical URL (join site.config.site.url with the current path), or rely on your host to serve a canonical link header. sitemap.xml and robots.txt are generated from your routes automatically.