Skip to content

Configuration Reference

dbward uses TOML configuration files for its three binaries:

BinaryConfig filePurpose
dbward-serverdbward-server.toml (via --config)Approval engine, policies, audit
dbward-agentdbward-agent.toml (via --config)Database execution, polling
dbward (CLI)~/.config/dbward/config.toml + ./dbward.tomlServer connection, project defaults

All files support variable expansion for secrets and environment-specific values.


state_dir = "/data"
[[databases]]
name = "app"
environments = ["production"]
FieldTypeRequiredDefaultDescription
state_dirStringDirectory for SQLite state and keys. Created on first start.
trusted_proxiesString[][]CIDR ranges trusted for X-Forwarded-For. See trusted_proxies.

Registers a database that the server will accept requests for.

[[databases]]
name = "analytics"
environments = ["staging", "production"]
FieldTypeRequiredDefaultDescription
nameStringLogical database identifier. Referenced in workflows and policies.
environmentsString[]Environments this database operates in.
[auth]
mode = "both"
default_role = "readonly"
FieldTypeRequiredDefaultDescription
modeString"token" if [auth.oidc] absent; "both" if [auth.oidc] presentAuthentication mode: "token", "oidc", "both". Requires Team license for "oidc"/"both".
default_roleStringRole assigned when no binding matches. Unset = reject unmatched users.

Requires auth.mode = "oidc" or "both" (explicit or implicit). Requires Team license.

[auth.oidc]
issuer_url = "https://auth.example.com/realms/dbward"
audience = "dbward"
FieldTypeRequiredDefaultDescription
issuer_urlStringOIDC issuer URL. Must be http:// or https://. Alias: issuer.
audienceString""Expected aud claim for JWT validation. At least one of audience or client_id must be non-empty.
jwks_uriStringOverride JWKS endpoint. Must be http:// or https:// if set.
client_idStringClient ID used as aud claim if set. Takes precedence over audience.
default_roleStringRole for OIDC users when no mapping matches. Falls back to [auth].default_role.

Maps OIDC claims to dbward roles.

[[auth.oidc.role_mappings]]
claim = "groups"
value = "dba-team"
role = "admin"
FieldTypeRequiredDefaultDescription
claimStringOIDC token claim name to inspect.
valueStringClaim value that triggers the mapping. Exact match.
roleStringdbward role to assign when matched.

Binds API token subjects or groups to roles.

[[auth.role_bindings]]
role = "admin"
subjects = ["alice", "bob"]
FieldTypeRequiredDefaultDescription
roleStringRole to assign. Must be a built-in or custom role.
subjectsString[][]Token subject identifiers to bind.
groupsString[][]Group names. All members receive this role.

Define custom roles and groups in TOML.

[[auth.roles]]
name = "dba"
permissions = ["request.create", "request.approve", "audit.view"]
[[auth.groups]]
name = "backend-team"
members = ["alice", "bob", "carol"]

[[auth.roles]]

FieldTypeRequiredDefaultDescription
nameStringRole identifier. Cannot redefine built-ins: admin, developer, readonly, agent-default.
permissionsString[]Granted permissions (e.g. "request.create", "request.approve", "*"). Full list →
databasesString[][]Restrict to specific databases. Empty = all.
environmentsString[][]Restrict to specific environments. Empty = all.

[[auth.groups]]

FieldTypeRequiredDefaultDescription
nameStringGroup identifier. Referenced in role_bindings and workflow approvers.
membersString[]Token subject identifiers belonging to this group.

Pre-provision users and manage their lifecycle via config.

[[users]]
id = "alice"
status = "active"
[[users]]
id = "bob"
status = "suspended"
FieldTypeRequiredDefaultDescription
idStringUser identifier (must match the subject_id used in authentication).
statusString"active"User status: "active" or "suspended".

Behavior on sync (server start / reload):

  • Setting status = "suspended" revokes all API tokens and cancels all pending requests for that user — equivalent to the API suspend endpoint.
  • Changing status back to "active" re-enables the user, but revoked tokens remain revoked. Issue new tokens after reactivation.
  • Removing a user from config revokes tokens, cancels requests, and deletes the user record.
  • If a user ID already exists with a different source (e.g., created via OIDC login), the config entry is skipped with a warning to prevent conflicts.

Defines approval requirements per database × environment × operation.

[[workflows]]
database = "app"
environment = "production"
operations = ["execute_dml", "migrate_up"]
require_reason = true
[[workflows.steps]]
mode = "all"
[[workflows.steps.approvers]]
role = "admin"
min = 1
FieldTypeRequiredDefaultDescription
databaseString"*"Scope filter. "*" matches all databases.
environmentString"*"Scope filter. "*" matches all environments.
operationsString[][]Operations filter. Empty = all. Values: execute_select, execute_dml, migrate_up, migrate_down, migrate_status, migrate_repair.
stepsStep[][]Approval steps. Empty = auto-approve.
require_reasonboolfalseReject requests without --reason.
allow_self_approveboolfalseAllow requester to approve own request.
allow_same_approver_across_stepsbooltrueAllow same person to approve multiple steps.
explainbooltrueAuto-run EXPLAIN on request creation.
pending_ttl_secsu64Request expires if not approved within this window. Falls back to retention.approval_ttl_secs.
statement_timeout_secsu64Override agent’s statement timeout. Capped by execution_policies.max_statement_timeout_secs.
FieldTypeRequiredDefaultDescription
modeString"all""all": every approver entry satisfied. "any": any single entry suffices.
approversApprover[]Approver requirements.

Approver entry (use exactly one of role, group, or user):

FieldTypeRequiredDefaultDescription
roleStringRole whose members can approve.
groupStringGroup whose members can approve.
userStringSpecific user subject.
minu321Minimum approvals needed from this entry.

Risk-based automatic approval.

[[auto_approve]]
database = "app"
environment = "staging"
risk = "low"
FieldTypeRequiredDefaultDescription
databaseString"*"Scope filter.
environmentString"*"Scope filter.
riskString"none"Max risk level: "none", "low", "medium", "high". "none" = disabled.
allow_read_onlybooltrueSELECT counts as Low risk.
allow_safe_ddlbooltrueCREATE TABLE/INDEX/VIEW counts as Low risk.
max_estimated_rowsu641000Threshold for large-table risk increase.

Static SQL analysis rules. Typos in field names cause startup error (deny_unknown_fields).

By default, high-risk destructive operations are blocked (rejected immediately). To relax rules for development environments, override them in your TOML config:

[sql_review]
no_where_delete = "warn" # or "off" to disable entirely
no_where_update = "warn"
drop_table = "off"
truncate = "off"
FieldTypeRequiredDefaultDescription
no_where_deleteString"block"DELETE without WHERE. Values: "block", "warn", "off".
no_where_updateString"block"UPDATE without WHERE.
drop_tableString"block"DROP TABLE.
drop_columnString"warn"ALTER TABLE DROP COLUMN.
not_null_without_defaultString"warn"NOT NULL column without DEFAULT.
create_index_not_concurrentlyString"warn"CREATE INDEX without CONCURRENTLY (PostgreSQL).
alter_column_typeString"warn"ALTER COLUMN TYPE.
truncateString"block"TRUNCATE.
mixed_ddl_dmlString"warn"DDL and DML in same request.
large_in_listString"warn"IN clause with excessive values.
[[webhooks]]
url = "https://hooks.slack.com/services/T.../B.../xxx"
format = "slack"
secret = "${WEBHOOK_SECRET}"
FieldTypeRequiredDefaultDescription
urlStringWebhook destination URL.
secretStringHMAC-SHA256 key. Sent in X-Dbward-Signature.
eventsString[][]Filter events. Empty = all.
formatString"generic"Payload format: "generic" (JSON) or "slack" (Block Kit).

Rate limiting and timeout per scope.

[[execution_policies]]
database = "app"
environment = "production"
max_executions = 3
statement_timeout_secs = 60
FieldTypeRequiredDefaultDescription
databaseString"*"Scope filter.
environmentString"*"Scope filter.
max_executionsu32Max executions per window. Unset = no limit.
execution_window_secsu64Time window for max_executions.
retry_on_failureboolAllow re-dispatch on failure. Unset = no retry.
statement_timeout_secsu32SQL timeout. Unset = use agent default (30s).
max_statement_timeout_secsu32Cap for workflow-level timeout override.
migration_statement_timeout_secsu32Statement timeout for migrations. Unset = unlimited (no timeout).
max_rowsu32Max result rows. Unset = no limit.
[retention]
request_ttl_days = 90
audit_ttl_days = 365
FieldTypeRequiredDefaultDescription
request_ttl_daysu6490Auto-delete completed requests after N days.
audit_ttl_daysu64365Auto-delete audit events after N days.
result_ttl_daysu6430Auto-delete stored results after N days.
approval_ttl_secsu6486400Approved requests expire if not resumed within this window.
[audit]
redaction = "literals"
FieldTypeRequiredDefaultDescription
redactionString"literals"SQL redaction: "literals" (mask values), "full" (hide SQL), "none".
[result_storage]
backend = "local"
FieldTypeRequiredDefaultDescription
backendString"local"Storage backend: "local" or "s3".
root_dirString"{state_dir}/results"Local backend directory.
max_persist_bytesusize10485760Results above 10 MB are not persisted.
bucketStringS3 bucket name. Required when backend = "s3".
regionStringAWS region for S3.
endpointStringCustom S3 endpoint (MinIO, localstack).
access_key_idStringS3 access key. Prefer IAM roles.
secret_access_keyStringS3 secret key.
path_styleboolfalsePath-style S3 URLs (set true for MinIO).
prefixString"results"Key prefix for S3 objects.

Note: [result_storage] is not hot-reloaded on SIGHUP. Changes require a process restart (task redeployment in ECS/Kubernetes).

In-memory relay for streaming results.

FieldTypeRequiredDefaultDescription
max_slotsusize10000Max concurrent result slots.
slot_ttl_secsu64600Slot removed after 10 min if unclaimed.
FieldTypeRequiredDefaultDescription
levelString"info"Log level: debug, info, warn, error.
formatString"text"Output format: "text" or "json". Overridden by DBWARD_LOG_FORMAT.

Slack integration for notifications and interactive approve/reject.

[slack]
bot_token = "${SLACK_BOT_TOKEN}"
signing_secret = "${SLACK_SIGNING_SECRET}"
channel = "C02C1EUJ0EN"
FieldTypeRequiredDefaultDescription
bot_tokenStringSlack Bot OAuth token (xoxb-...).
signing_secretStringSlack signing secret for request verification.
channelString"#db-approvals"Default channel (ID or name).
channelsMap{}Per-environment override. Key = env, value = channel.
trusted_proxies = ["10.0.0.0/8", "172.16.0.0/12"]

When empty (default), the direct connection IP is used. Required behind a load balancer for accurate audit log IPs.


[server]
url = "http://localhost:3000"
agent_token = "${DBWARD_AGENT_TOKEN}"
[databases.app.production]
url = "${DATABASE_URL}"
FieldTypeRequiredDefaultDescription
agent_idStringhostnameUnique agent identifier.
poll_interval_msu641000Milliseconds between poll requests.
max_concurrent_tasksu322Max parallel executions.
drain_timeout_secsu6460Graceful shutdown wait.
statement_timeout_secsu6430Default SQL timeout.
lease_duration_secsu64300Job lease before server reclaims.
operationsString[]allOperation types to handle. Unset = all.
startup_retry_initial_msu641000Initial retry backoff.
startup_retry_max_msu6415000Max retry backoff.
startup_max_wait_secsu6460Max startup wait. 0 = wait forever.
FieldTypeRequiredDefaultDescription
urlStringServer URL to poll.
agent_tokenStringAuth token. Use ${DBWARD_AGENT_TOKEN} expansion.
allow_insecureboolfalseAllow HTTP connections to non-local servers. The agent refuses to start with external HTTP unless this is true. See Security Hardening.
[databases.app.production]
url = "postgres://user:pass@db:5432/app"
FieldTypeRequiredDefaultDescription
urlStringDatabase connection URL. Scheme = driver (postgres:// or mysql://).
FieldTypeRequiredDefaultDescription
enabledbooltrueEnable schema collection.
sync_on_startupbooltrueCollect on agent startup.
interval_secsu640Periodic interval. 0 = startup + after migrations only.

  1. Environment variables (DBWARD_SERVER_URL, DBWARD_TOKEN, etc.)
  2. --config flag (standalone mode — no merging)
  3. Project config (./dbward.toml or DBWARD_CONFIG)
  4. Global config (~/.config/dbward/config.toml)
FieldTypeRequiredDefaultDescription
urlStringServer URL.
tokenStringAPI token. Mutually exclusive with [server.oidc].
allow_insecureboolfalseAllow HTTP connections to non-local servers. Suppresses the insecure-transport warning. Does not override OIDC+HTTP rejection.
FieldTypeRequiredDefaultDescription
issuerStringOIDC issuer URL.
client_idStringOIDC client ID for PKCE.
discovery_urlStringOverride discovery endpoint.
backchannel_urlStringOverride token endpoint.
browser_urlStringOverride authorize URL.
FieldTypeRequiredDefaultDescription
default_databaseStringDatabase when --database omitted.
default_environmentStringEnvironment when -e omitted.
migrations_dirPath"./migrations"Migration SQL directory.
FieldTypeRequiredDefaultDescription
dirPath"~/.dbward/results"Local directory for saving query results.
formatString"table"Default result format: table, json, csv, vertical.

Per-database override:

[databases.analytics]
migrations_dir = "migrations/analytics"

VariableDescription
DBWARD_CONFIGProject config path. Enables standalone mode.
DBWARD_SERVER_URLOverride server URL.
DBWARD_TOKENOverride API token.
DBWARD_DATABASEDefault database.
DBWARD_ENVDefault environment.
DBWARD_AGENT_TOKENAgent token (referenced via ${DBWARD_AGENT_TOKEN}).
DBWARD_ALLOW_INSECUREtrue or 1 to allow HTTP to non-local servers. Overrides config file setting.
DBWARD_LOG_FORMATForce "json" log output. Overrides [logging].format.

All TOML config files support shell-style variable expansion:

SyntaxBehavior
${VAR}Required — startup error if unset.
${VAR:-default}Use default if unset.
${VAR:-}Empty string if unset.
[server]
agent_token = "${DBWARD_AGENT_TOKEN}"
[databases.app.production]
url = "${DATABASE_URL:-postgres://localhost:5432/app}"