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` configjobs = 0 # render worker processes: 0 = one per CPU (max 8), 1 = serialbase = "" # public sub-path for project Pages, e.g. "/repo/" (also EPRESSO_BASE)[markdown]backend = "native" # renderer: "native" (Python); "rust" = optional acceleratorhighlight = 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 | topplugins = ["mypkg:MyPlugin"] # dotted-path plugin specs[plugin.my_plugin] # options keyed by the plugin's name, read via caps.optionskey = "value"# Docs under a path in this site: the bundled epresso_docs plugin.# [plugin.epresso_docs]# base = "/docs/"# sources = [{ source = "docs" }][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 the project root, as are site.toml and content.config.py. Content collection base paths are resolved against the same 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.