Skip to content
cronpad
Self-hosting / Configuration reference

Configuration reference

cronpad reads settings from built-in defaults, then an optional TOML file (cronpad.toml in the working directory, or --config <path>), then environment variables, then command-line flags; later sources win. Any setting can be set by environment variable: prefix CRONPAD_, uppercase the key, and join nested sections with a double underscore. Invalid configuration stops the server at startup with a list of every problem.

[database]
path = "/data/cronpad.db"

is the same as

CRONPAD_DATABASE__PATH=/data/cronpad.db

Durations use Go units (ms, s, m, h) plus d for days: "500ms", "30s", "1h30m", "30d". Lists in environment variables are comma-separated: CRONPAD_AUTH__ALLOWED_EMAIL_DOMAINS=example.com,example.org.

Top level

KeyDefaultDescription
mode"selfhosted"selfhosted or hosted. hosted applies safe defaults for a public, multi-tenant server; see Security.

server

KeyDefaultDescription
addr":8080"Address the process listens on.
public_url"http://localhost:8080"The URL users reach cronpad at, e.g. https://cron.example.com. Used for OAuth callbacks, links in alert emails, and to mark cookies Secure when it’s https. Set it whenever cronpad is behind a proxy or on a domain.
read_timeout"15s"Maximum time to read a request.
write_timeout"30s"Maximum time to write a response.
shutdown_grace"30s"How long SIGTERM waits for in-flight runs. Make your orchestrator’s stop timeout longer than this.
trusted_proxies[]CIDRs whose X-Forwarded-For is trusted.

ui

KeyDefaultDescription
dashboardtrueServe the dashboard at /. false disables the dashboard; the API, /auth, /mcp and health endpoints keep working.
cors_origins[]Exact origins (no wildcards, no paths; for example https://www.example.com) allowed to call /api/ from a browser. Leave empty for normal self-hosting: the dashboard and API share an origin. Set it only when another site’s browser JavaScript calls your API, such as a page embedding the schedule preview. Cookies are never sent cross-origin, so those calls reach only public endpoints or use an API key. Env: CRONPAD_UI__CORS_ORIGINS (comma-separated).

database

KeyDefaultDescription
path"./data/cronpad.db"Control database: users, workspaces, jobs, keys, secrets, alert config.
history_path"./data/history.db"History database: runs, attempts, audit log, alert outbox, stats.
busy_timeout"5s"How long SQLite waits on a lock before failing.
run_migrationstrueApply migrations on startup.

Both files must be on a local or block-storage filesystem, never NFS/SMB.

queue

KeyDefaultDescription
path""The SQLite queue file. Empty means <name>-queue.db beside database.path (./data/cronpad-queue.db by default), so two servers with differently named databases in one directory never share a queue. It is a rebuildable index: never back it up or restore it. Must differ from both database paths.

Releases that used Redis read a [redis] section; it is now ignored with a warning at startup. See Upgrading from a Redis-based version.

scheduler

See Scheduling engine for what these control.

KeyDefaultDescription
tick_interval"100ms"Longest the claim loop sleeps when nothing is due sooner.
results_flush_interval"0s"0s = group commit: the result writer commits as soon as it is free and batches whatever arrived meanwhile. A positive value (1ms through 1s) instead waits for a fixed ticker to grow batches.
results_max_batch500Commit immediately at this command count; 1 through 10000.
delivery_mode"durable"durable waits for admission commits; opt-in fast overlaps delivery and commits. Requires receiver idempotency; allowed in hosted mode.
claim_batch500Maximum occurrences claimed at once.
lease_duration"60s"In-flight lease. Renewed while a sink runs, so it only expires when a worker crashes or hangs.
reaper_interval"5s"How often expired leases are returned to the queue.
lock_ttl"15s"Dispatcher lock lifetime; renewed every third of it.
reconcile_interval"10s"How often overdue jobs are checked for lost queue entries.
overdue_grace"30s"How far past its fire time a job must be before it counts as overdue.
full_reconcile_interval"6h"Full database ↔ queue sweep (also at startup and when queue data loss is detected).
sla_threshold"5s"Default start lag above which a run breaches its SLA. Jobs can override it.
default_misfire_policy"fire_once"fire_once, fire_all or skip. See Misfires.
misfire_fire_all_cap10Maximum missed occurrences replayed by fire_all.

workers

KeyDefaultDescription
count64Concurrent sink executions.
queue_size1024Hand-off buffer between the claim loop and workers.

sinks.webhook

KeyDefaultDescription
per_host_rate_limit20Hosted-only requests/second per destination host across workspaces; token bucket delays excess. 0 disables; self-hosted mode leaves it off.
enabledtrue
default_timeout"30s"Per-attempt timeout when a job doesn’t set one.
max_timeout"120s"Largest timeout a job may set.
max_response_bytes65536Response bytes read and stored per attempt.
allow_private_networkstrue (false in hosted mode)Allow webhooks to loopback, private and link-local addresses.
user_agent"cronpad/{version}"

sinks.command

KeyDefaultDescription
enabledtrue (false in hosted mode)Allow command jobs.
shell"/bin/sh"Shell used when a job sets shell: true.
allowed_commands[]If non-empty, only these executables may run, and shell: true is rejected.
default_timeout"60s"
max_output_bytes65536Captured stdout+stderr per attempt.
env_passthrough[]Server environment variables passed to commands, besides PATH, HOME and LANG.

retry.defaults

KeyDefaultDescription
max_attempts3Including the first attempt.
backoff"exponential"exponential or fixed.
initial_interval"10s"
max_interval"10m"
multiplier2.0
jitter0.2±fraction applied to each wait.

auto_disable

KeyDefaultDescription
enabledtrueDisable jobs after too many consecutive failed runs.
consecutive_failures20Default threshold.
notifytrueEmail workspace owners when a job is disabled.

limits

0 means unlimited. Self-hosted defaults are unlimited; cronpad Cloud sets its own values.

KeyDefaultDescription
max_jobs_per_workspace0
min_interval"1s"Shortest allowed time between a job’s occurrences.
max_runs_per_month_per_workspace0UTC calendar-month cap; automatic retries do not count.
over_quota"block"block records excess occurrences as skipped; allow keeps delivering and counting.
max_concurrent_runs_per_workspace0Maximum concurrent admissions per workspace; excess claims wait 250ms.
max_alert_emails_per_day0Ordinary alert emails per workspace per UTC day; excess is suppressed.
max_runs_per_day_per_workspacedeprecatedConverted ×30 to monthly with a startup warning; explicit monthly wins.
max_api_keys_per_workspace0Unlimited on self-hosted; hosted default 20.
max_retry_attempts0Upper bound for a job’s max_attempts.
api_rate_limit_per_minute600Per API key or session.

retention

See Data retention. "0" keeps data forever.

KeyDefaultDescription
runs"30d"Runs and their attempts.
attempt_bodies"7d"Response bodies and command output only.
store_success_bodiesfalseAlso store bodies of successful attempts.
audit_log"30d"
alert_outbox"30d"Sent, failed and suppressed alerts. Pending alerts are never deleted.
job_stats_daily"400d"Daily rollups behind dashboard charts.
janitor_interval"5m"
janitor_batch1000Rows deleted per transaction.

auth

See Authentication.

KeyDefaultDescription
session_lifetime"720h"
allowed_email_domains[]If set, only these email domains may sign in.
allow_signupfalsetrue lets anyone who can sign in create an account. When false, only existing users sign in, except the first user of an empty server (First sign-in).
dev_loginfalsePasswordless local login for development. Never enable on a reachable server.
google.client_id, google.client_secret""
github.client_id, github.client_secret""

secrets

KeyDefaultDescription
encryption_key""32 random bytes, base64. Required to use secrets. Generate with openssl rand -base64 32. Keep a copy: backups are useless without it.

alerts.email

KeyDefaultDescription
enabledfalse
smtp_host, smtp_port"", 587STARTTLS on 587, implicit TLS on 465.
username, password""
from"cronpad <alerts@example.com>"

telemetry

See Observability.

KeyDefaultDescription
service_name"cronpad"
otlp_endpoint""OTLP collector endpoint. Empty disables OTLP export.
otlp_protocol"grpc"grpc or http.
otlp_logsfalseAlso export logs over OTLP.
prometheus_addr""e.g. ":9090" to serve /metrics on a separate port.
traces_sample_ratio0.1Fraction of runs traced.

logging

See Logging.

KeyDefaultDescription
level"info"debug, info, warn, error.
format"json"json or logfmt.
add_sourcefalseInclude source=file.go:123.

mcp

KeyDefaultDescription
enabledtrueServe the MCP server.
path"/mcp"

Example

[server]
public_url = "https://cron.example.com"
trusted_proxies = ["10.0.0.0/8"]

[auth.github]
client_id = "Iv1.0123456789"
# client_secret from CRONPAD_AUTH__GITHUB__CLIENT_SECRET

[alerts.email]
enabled = true
smtp_host = "smtp.postmarkapp.com"
from = "cronpad <cron@example.com>"

[logging]
format = "logfmt"

[retention]
runs = "90d"

auth.oidc

One optional instance-wide OIDC login provider; see Authentication for Authentik and Keycloak setup. Environment variables use the prefix CRONPAD_AUTH__OIDC__.

KeyDefaultDescription
issuer""Issuer URL, used for discovery; empty disables the provider.
client_id""OIDC client ID, required when issuer is configured.
client_secret""Confidential client secret; prefer an environment variable.
display_name"SSO"Label displayed on the dashboard sign-in button.
scopes["openid", "email", "profile"]Requested scopes; must include openid.
require_email_verifiedtrueReject identities without verified email; disabling trusts the provider’s email for linking.

Register <public_url>/auth/oidc:default/callback as the provider’s exact redirect URI. Discovery and token verification errors reject login. This provider counts toward the startup OAuth-provider requirement.