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
site.toml— base configuration.site.<env>.toml(when--env <name>orEPRESSO_ENVis set) — deep-merged oversite.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
pythonfrom 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.