config.json Reference
content/config.json is entirely optional and hot-reloads with the rest of content/. Every field below is optional too, with a sensible default filling in whatever's missing.
A config using most of them at once:
content/config.json
json{
"title": "Acme Status",
"titleTemplate": ":title · Acme Status",
"description": "Uptime and incident history for Acme's public services.",
"lang": "en",
"culture": "en-GB",
"theme": "ocean",
"structure": "dashboard",
"author": "Acme Ops",
"favicon": "🛡️",
"scrollIndicator": true,
"noIndex": { "pages": true },
"socialLinks": [
{ "icon": "github", "url": "https://github.com/acme", "title": "GitHub" }
],
"menu": [
{ "title": "Status", "path": "/" },
{ "title": "About", "path": "/about/" }
],
"footerMenu": [
{ "title": "Status API", "path": "/api/status", "external": true }
],
"footer": "© {year} {author}. Built with [Warden](https://github.com/melosso/warden).",
"monitoring": {
"intervalSeconds": 60,
"retentionDays": 90,
"group": "type",
"targets": [
{ "id": "site", "name": "Main site", "url": "https://acme.example" }
]
}
}Site
| Field | Description |
|---|---|
title |
The site name: browser tab, social previews, and the {title} token elsewhere. |
titleTemplate |
Wraps title for the tab text, e.g. ":title · Acme". :title is the placeholder. |
description |
The default meta description, used on any page that doesn't set its own. |
brand |
Text shown next to the logo in the topbar. Falls back to title. |
brandImage |
A logo image, replacing brand in the topbar. |
image |
Default social preview image for pages that don't set their own cover. |
favicon |
An emoji or an image path for the browser tab icon. |
author |
The name in the {author} footer token. organization, organisation, and owner are aliases, checked in that order, ahead of author. |
Language and dates
| Field | Description |
|---|---|
lang |
The page's <html lang> attribute and default UI language. |
culture |
Date and number formatting, e.g. "en-GB". |
locale |
Either a bare code string ("nl") or an object: { "culture": "en-GB", "code": "en" }. Merges with culture above. |
Appearance
| Field | Description |
|---|---|
theme |
One of the built-in palettes. See the guide for the full list. Add " dark" or " light" to pin a mode and drop the toggle. |
structure |
clean (default, a flat list) or dashboard (card grid). Independent of theme; any theme pairs with either. |
scrollIndicator |
Set false to hide the reading-progress bar at the top of the page. |
Navigation
| Field | Description |
|---|---|
menu |
Topbar links: [{ "title": "...", "path": "..." }]. An entry with items renders as a dropdown instead of a link. external: true opens it in a new tab. |
footerMenu |
Same shape, rendered in the footer. |
footer |
Markdown for the footer note. Tokens: {year}, {author}, {title}. Falls back to a plain copyright line built from title. |
socialLinks |
Icon links in the topbar: [{ "icon": "github", "url": "...", "title": "..." }]. |
head |
Raw tags injected into <head>: [{ "tag": "meta", "attrs": { "name": "...", "content": "..." }, "content": "..." }]. |
Search visibility
| Field | Description |
|---|---|
noIndex.pages |
Set true to noindex every standalone page under content/pages/ at once, without touching each page's own front matter. A page's own noindex: true still applies regardless. |
redirectHosts |
Off-site hosts a page's redirect front matter is allowed to send readers to. Same-host redirects always work without listing anything here. |
Monitoring
monitoring controls what gets checked and how the status page groups it. See the guide for a walkthrough; this is the full field list.
| Field | Description |
|---|---|
intervalSeconds |
How often every target is checked. Default 60. |
retentionDays |
How long heartbeat history is kept before it's pruned. Default 30. |
group |
"type" sections monitors by type, "custom" sections them by each target's own group field (falling back to its type when unset). Unset renders one ungrouped list or grid. Works with every structure. |
incidentWindowDays, incidentMaxShown |
How far back and how many resolved incidents show on the status page. Defaults 7 and 10. |
incidentUrlPattern |
"year" gives every incident a /incidents/{year}/{slug}/ URL, "year-month" gives /incidents/{year}/{month}/{slug}/, both taken from the incident's own date, regardless of which folder the file lives in. Unset (default) uses the file's own path under content/incidents/ as-is. |
maintenanceWindowDays, maintenanceMaxShown |
How far ahead and how many upcoming maintenance windows show. Defaults 14 and 10. |
targets |
The list of monitors, covered below. |
Target fields
Every target needs id (a stable slug, it's the database key) and name (the display label). Everything else depends on type.
| Field | Applies to | Description |
|---|---|---|
type |
all | http (default), service_backend, ping, tcp, database, ftp, sftp, dns, or ssl. |
url |
http, service_backend |
The address to request. |
host, port |
everything except http/service_backend |
Where to connect. Ports default per type: 21 for ftp, 22 for sftp, 443 for ssl. |
expectedStatus |
service_backend |
HTTP status the response must match. Default 200. |
expectedJsonPath, expectedValue |
service_backend |
A JSON path into the response body (e.g. $.status) and the value it must equal. |
expectedIp |
dns |
The IP the hostname must resolve to. Left unset, any successful resolution counts as up. |
dnsServer |
dns |
Query this resolver directly instead of the OS default. |
family |
dns |
"ipv4" or "ipv6" to query one record type only. Unset queries both. |
warnDaysBefore |
ssl |
How many days before certificate expiry the check starts failing. Default 14. |
secure |
ftp |
Set true to require an explicit AUTH TLS upgrade after connecting. |
dbType |
database |
Informational only; the check itself is a TCP reachability probe. |
insecure |
http, service_backend |
Set true to skip TLS certificate validation, for a self-signed internal service. |
retries |
all | Consecutive failures allowed before the target is recorded down. Default 0, down on the first failed check. |
group |
all | This target's own group heading, used when monitoring.group is "custom". |
A few examples across types:
content/config.json
json{
"monitoring": {
"targets": [
{ "id": "site", "name": "Main site", "url": "https://acme.example" },
{ "id": "api", "name": "API health", "type": "service_backend", "url": "https://api.acme.example/healthz", "expectedJsonPath": "$.status", "expectedValue": "ok" },
{ "id": "db", "name": "Postgres", "type": "tcp", "host": "db.internal", "port": 5432, "retries": 2 },
{ "id": "cert", "name": "Certificate", "type": "ssl", "host": "acme.example", "warnDaysBefore": 21 },
{ "id": "resolver", "name": "DNS", "type": "dns", "host": "acme.example", "expectedIp": "203.0.113.10" }
]
}
}