Synadia Insights
Configuration
Insights uses a layered configuration system. Every setting can be specified through CLI flags, environment variables, or a YAML config file.
Priority Order
When the same setting is defined in multiple places, the highest-priority source wins:
- CLI flags (e.g.,
--server nats://host:4222) - Environment variables (e.g.,
INSIGHTS_NATS_SERVER=nats://host:4222) - YAML config file (via
--config,INSIGHTS_CONFIG, or a default search path; see Config File) - Built-in defaults
Config File
--config (or -c) is a global flag, so every subcommand can be driven from one file, not just the server. This matters with the default embedded NATS sink: the server serves its API on sink.port, and insights db query reaches it via the top-level nats: section. Pin both in one file and point every command at it:
# config.yaml
sink:
port: 4222 # server binds the embedded NATS here
nats:
server: nats://127.0.0.1:4222 # clients (query, checks, ops, ...) connect here
insights -c config.yaml # run the server
insights db query -c config.yaml "SELECT 1" # query it — no --server needed
The config file is found from three sources, each optional, in increasing precedence (later wins):
<user-config-dir>/insights/config.yaml: e.g.~/.config/insights/config.yamlon Linux,~/Library/Application Support/insights/config.yamlon macOS../insights.yaml: auto-discovered in the working directory.INSIGHTS_CONFIG: an explicit path set via the environment.
An explicit --config/-c flag overrides all of these. With a file at one of the default locations, a bare insights db query "SELECT 1" works with no flags. Per-setting environment variables (INSIGHTS_*) still override any config file (see Priority Order).
./insights.yaml is read from the current working directory, so any directory you run insights from can supply configuration (as with git, cargo, and similar tools). Avoid running insights from untrusted or world-writable directories, or pass --config explicitly. CLI flags and INSIGHTS_* environment variables always override the file.
Keys the configuration does not define are ignored without a warning, and insights config check does not report them either, so a misspelled or removed key leaves its setting at the default. Compare a file against the sections below when a value seems to have no effect.
An annotated example of every option with its default:
# Insights Configuration Example
#
# This file shows all available configuration options with their defaults.
#
# Loading this config (any subcommand, not just the server):
# - insights -c config.yaml (explicit flag, highest precedence)
# - INSIGHTS_CONFIG=config.yaml insights ...
# - place it at ./insights.yaml or <user-config-dir>/insights/config.yaml
# to have it discovered automatically with no flag
# The top-level nats: section drives client subcommands (query, checks, ops, web, mcp, http, ...);
# pin sink.port and nats.server together so one file serves both sides.
#
# The collector (`insights-collector serve`) reads
# the same file but uses only the data-dir/node/system/sys/scraper/sink/license/
# updater/telemetry settings; the db/indexer/web/prometheus sections are inert
# there (there is no local database).
#
# Configuration priority (highest wins):
# 1. CLI flags (e.g., --server; --nats.server is a hidden alias)
# 2. Environment variables (e.g., INSIGHTS_NATS_SERVER)
# 3. Config file (this file)
# 4. Defaults
#
# The subsystem on/off switches below (scraper/indexer/web/simulator/prometheus/
# updater/telemetry `enabled:`) are spelled as bare shorthands outside this file --
# --web=false on the command line, INSIGHTS_WEB=false in the environment. In
# YAML the section is a map, so use its enabled: key as shown here.
# Log level: debug, info, warn, error
log-level: 'info'
# License configuration, for trial builds (the -licensed archives and the
# insights-licensed image). Provide either a raw JWT string or a path to a file
# containing the JWT. If both are set, the file takes precedence.
# A trial build requires it unless the simulator is enabled or the node runs
# neither the indexer nor the scraper. Other builds require no license; leave it
# empty there, since a license that is set is still verified at startup.
license:
# Raw license JWT token string.
# Env: INSIGHTS_LICENSE_TOKEN
token: ''
# Path to a file containing the license JWT.
# Env: INSIGHTS_LICENSE_FILE
file: ''
# Base directory for persistent storage (DuckDB database + JetStream data).
# If empty, a temporary directory is created and data is lost on restart.
# Set this for persistent deployments.
data-dir: ''
# Node identity: names this process for the node-scoped API space
# ($INS.node.<id>.ops.pprof, ...) and as a stable label for operator tooling.
# Defaults to the id of the single system this node serves, which survives a
# reschedule where the hostname would not. A node serving several systems must
# be named; a web node, serving none, falls back to the hostname sanitized to a
# subject-safe token. Allowed characters: letters, digits, '_', '-'.
node:
# Env: INSIGHTS_NODE_ID
id: ''
# Operator-assigned labels describing where this process runs. They are
# reported on $INS.ping, so `insights node list` and the web Nodes tab can
# filter and group by them (`env=prod`). Nothing addresses a subject with
# them and no behaviour keys off them. Keys allow letters, digits, '_', '-'
# and '.'; values are free text without control characters. Max 16 pairs.
# Set here rather than by flag or env — a map has no readable flag form.
# metadata:
# region: us-east-1
# rack: b12
# System identity: names the monitored NATS system's API subtree
# ($INS.sys.<id>.db.query, ...). Operator-assigned — no stable NATS system
# identifier can be derived. Allowed characters: letters, digits, '_', '-'.
system:
# Env: INSIGHTS_SYSTEM_ID
id: 'default'
# Operator-assigned labels describing the monitored system, on the same terms
# as node.metadata above. Declared where the system is scraped: a node that
# indexes a collector-fed system without scraping it refuses to start with
# this set, because the collector is what describes the system. The
# multi-system list below takes the same block per entry.
# metadata:
# env: prod
# team: platform
# Multiple systems (optional). One instance can own several monitored systems,
# each with its own DuckDB instance, JetStream stream, and $INS.sys.<id>.* API.
# Set this list ONLY for a node monitoring more than one system; a single-system
# node — the usual deployment, a collector, a federated instance — uses the flat
# system:/sys:/scraper:/sink: config above and leaves this empty.
#
# systems: is mutually exclusive with system.id / sys / the flat scraper. A node with this list
# always indexes (indexer.enabled must be true), and cannot run the simulator.
# The top-level db: section becomes the per-system default; each entry overrides
# it.
#
# systems:
# # Outbound scraper: this node both scrapes and indexes this system. A `scrape`
# # block makes it scraped locally; omit it for a collector-fed system whose
# # stream a NATS mirror fills.
# - id: "core-prod"
# scrape:
# nats:
# server: "nats://core.internal:4222"
# creds: /etc/insights/core-prod.creds
# interval: 20s # falls back to scraper.interval
# # timeout: 30s # falls back to scraper.timeout
# retention: 24h # stream buffer depth (falls back to sink.retention); the DB keeps history
# db: # per-instance DuckDB sizing (overrides the top-level db:)
# memory-limit: "8GiB"
# check-thresholds: # per-system overrides, merged per code onto the top-level set
# server-003:
# cpu_percent: 80
# metadata: # labels for filtering and grouping; only on an entry with a scrape block
# env: prod
# team: platform
# disabled-checks: # unioned with the top-level list, never subtracted from it:
# - account-012 # an entry can turn a check off, not back on
# # Collector-fed: no scrape block. That is the whole declaration — this node
# # creates the system's stream as a JetStream mirror of the one a collector
# # fills, and only indexes it.
# - id: "edge-west"
# retention: 6h # buffer depth, enforced by pruning whole epochs
# #
# # Nothing else is required. The stream is named "mirror_<id>", the origin
# # is the collector's "scrape_<id>" — the same id, derived on both sides —
# # and the collector is asked over $INS.sys.<id>.ops.sink.info for the names,
# # subject prefix, domain and scrape cadence it actually uses.
# #
# # Set this only when the origin's JetStream is reached by something other
# # than a domain — a subject mapping or an account import under a prefix of
# # your choosing, which exists on this side and so cannot be discovered.
# # mirror-api-prefix: "JS.edge-west.API"
# #
# # Stream shape. Every field is optional; name defaults to "mirror_<id>"
# # here and "scrape_<id>" for a scraped system, and the sizing falls back to
# # the top-level sink:. A mirror must not share its origin's name:
# # $JS.FC.<stream>.> flow-control subjects are not domain-prefixed.
# # stream:
# # name: "mirror_edge_west"
# # replicas: 3 # requires a clustered sink (sink.embed: false)
# # storage: "file" # or "memory"
# Top-level NATS connection for serving the API.
# These credentials are used by the API server and as defaults
# for indexer and scraper if not explicitly configured.
nats:
# NATS server URL
server: ''
# Path to credentials file (.creds)
creds: ''
# NATS context name (from nats context)
context: ''
# Username for basic auth
user: ''
# Password for basic auth
password: ''
# NKey seed for NKey+JWT auth (requires jwt to also be set)
nkey: ''
# User JWT for authentication.
# If nkey is also set, used as NKey-signed JWT auth.
# If standalone, used as a bearer token (server must have bearer_token enabled).
jwt: ''
# TLS certificate path
tls-cert: ''
# TLS key path
tls-key: ''
# TLS CA certificate path
tls-ca-cert: ''
# Perform TLS handshake first (before NATS protocol)
tls-first: false
# SOCKS proxy URL for connections
socks-proxy: ''
# Request/reply inbox prefix. Empty uses the NATS default (_INBOX).
# Set this when the account is not granted _INBOX.>
inbox-prefix: ''
# NATS system account credentials for the target system being scraped.
# This connection is used to issue $SYS requests to collect metrics.
# This is required if the simulator is disabled.
sys: {}
# Database configuration for DuckDB.
db:
# DuckDB memory limit. Caps the buffer pool to prevent swapping on large databases.
# Examples: "4GiB", "8GiB", "16GiB". Default: "4GiB".
# Env: INSIGHTS_DB_MEMORY_LIMIT
memory-limit: '4GiB'
# DuckDB worker threads. 0 uses DuckDB's default (all cores).
# Reduce to leave cores for the indexer and web server.
# Env: INSIGHTS_DB_THREADS
threads: 0
# Max wall-clock time a single $INS.db.query statement may run before it is interrupted.
# Guards against a pathological query (e.g. a count over a cartesian relation, which is pure
# CPU and never trips the memory limit) pegging the server. 0 disables the cap.
# Env: INSIGHTS_DB_QUERY_TIMEOUT
query-timeout: 2m
# Max rows the non-streaming $INS.db.query endpoint may return. That endpoint buffers the
# whole result before responding, so an unbounded SELECT * could return enough rows to run
# the server out of memory (the DuckDB memory_limit does not bound this buffered reply).
# Oversized results are rejected with a 413 pointing at the streaming endpoint
# $INS.db.query.stream. 0 disables the cap.
# Env: INSIGHTS_DB_QUERY_MAX_ROWS
query-max-rows: 100000
# Streaming query endpoint ($INS.db.query.stream). Pushes results as windowed Arrow IPC
# chunks (rendered to CSV/JSON client-side) so arbitrarily large results never accumulate
# in memory on either side, so it is not subject to the query-max-rows cap
# (it carries only the large query-stream.max-rows safety limit below).
query-stream:
# Max chunks kept in flight unacknowledged before the server pauses producing. Bounds
# client-side buffering to roughly window × chunk-size.
# Env: INSIGHTS_DB_QUERY_STREAM_WINDOW
window: 16
# Target size of each chunk message (IEC units). Clamped below the connection max_payload.
# Env: INSIGHTS_DB_QUERY_STREAM_CHUNK_SIZE
chunk-size: 512KiB
# Max time to produce each Arrow batch (incl. the first), bounding a stalled or slow-to-
# first-row query. 0 disables.
# Env: INSIGHTS_DB_QUERY_STREAM_BATCH_TIMEOUT
batch-timeout: 30s
# Abort the scan if the client sends no acknowledgement within this window (dead/Ctrl-C'd
# consumer). 0 disables.
# Env: INSIGHTS_DB_QUERY_STREAM_ACK_IDLE_TIMEOUT
ack-idle-timeout: 30s
# Per-buffer Arrow IPC compression for streamed chunks: none, lz4, or zstd. Clients
# decompress transparently. Compression uses additional CPU; leave none unless bandwidth
# is the bottleneck.
# Env: INSIGHTS_DB_QUERY_STREAM_COMPRESSION
compression: none
# Abort a streamed query after this many rows, failing fast with guidance to scope it.
# Rows are counted as they are produced, so the cap bounds the work an unscoped SELECT *
# over a per-epoch table/view (e.g. hx.conns, millions of rows across all history) can do
# before it is stopped. Bounded queries (epoch-scoped, entity-scoped, or LIMITed) never
# reach it. 0 disables the cap for operators who need very large exports.
# Env: INSIGHTS_DB_QUERY_STREAM_MAX_ROWS
max-rows: 1000000
# Retention policy for automatic epoch cleanup from DuckDB.
retention:
# How long to keep data. 0 disables retention.
# Env: INSIGHTS_DB_RETENTION_DURATION
duration: 768h
# Minimum time between retention sweeps. A sweep runs on the indexer right after
# the first epoch committed past the interval, never concurrently with a commit.
# Env: INSIGHTS_DB_RETENTION_INTERVAL
interval: 10m
# Live memory profiler: samples duckdb_memory() so `ops sizing` and
# `ops memory` can use measured peaks instead of estimates.
memory-profile:
# Enable the background memory profiler.
# Env: INSIGHTS_DB_MEMORY_PROFILE_ENABLED
enabled: true
# How often to sample duckdb_memory() (metadata-cheap).
# Env: INSIGHTS_DB_MEMORY_PROFILE_INTERVAL
interval: 2s
# Rolling window retained in memory for the peak and the Realtime chart.
# Env: INSIGHTS_DB_MEMORY_PROFILE_WINDOW
window: 15m
# Scraper configuration for collecting metrics from NATS servers.
scraper:
# Enable or disable the scraper
enabled: true
# Timeout for scrape requests
timeout: 30s
# Interval between scrapes
interval: 1m
# Optional NATS connection for publishing scraped data.
# If not specified, uses the indexer NATS config (or top-level NATS).
nats: {}
# Optional filter controlling which discovered servers are scraped. Matching
# is exact (by server name, cluster name, or tag). Deny takes precedence over
# allow; when any allow list is set, a server must match it to be scraped.
# Excluded servers receive no monitoring requests. Omit to scrape every
# discovered server.
filter:
# Scrape only servers matching these. When all allow lists are empty, every
# server not denied is scraped.
allow:
servers: []
clusters: []
tags: []
# Never scrape servers matching these (takes precedence over allow).
deny:
servers: []
clusters: []
tags: []
# Indexer configuration for processing and storing scraped data.
indexer:
# Enable or disable the indexer
enabled: true
# Start consuming from the latest message in the stream
stream-latest: false
# Start consuming from a specific epoch number
stream-epoch: 0
# Filter specific Z endpoints to process (comma-separated: varz,jsz,connz)
stream-filters: ''
# Downsample interval for consuming epochs
stream-interval: 0s
# Optional NATS connection for consuming scraped data.
# If not specified, uses the top-level NATS config.
nats: {}
# Sink configuration for the embedded NATS server.
sink:
# Use an embedded NATS server for storing scraped data.
embed: true
# Optional NATS server config file for the embedded server.
# The file is parsed first, then Insights-specific settings are applied on top.
# config-file: /path/to/nats-server.conf
# Host to bind the embedded NATS server to
host: '127.0.0.1'
# Port to bind the embedded NATS server to (0 = random)
port: 0
# JetStream stream name for storing scraped data.
# The collector derives this from system.id ("scrape_<id>") when the id is
# set and this is left at the default, so a central node mirroring the collector lands
# on the same name without being told it.
stream: 'scrape'
# Batch size for sink operations
batch-size: 500
# How long to keep scraped data in the sink stream. 0 disables retention.
# Enforced by pruning whole epochs, not by the stream's max age: a
# message-level limit would leave the indexer a scrape truncated mid-epoch.
# Env: INSIGHTS_SINK_RETENTION
retention: 24h
# Replica count for the sink stream. Requires a clustered sink — the embedded
# server is a single node, and embed: true with replicas > 1 is rejected.
# Env: INSIGHTS_SINK_REPLICAS
replicas: 1
# Storage class for the sink stream: "file" or "memory". The stream is a
# buffer — the database holds the history — so memory storage is a reasonable
# choice for a system that can afford to lose the buffer on restart.
# Env: INSIGHTS_SINK_STORAGE
storage: 'file'
# Embedded NATS simulator configuration.
# When enabled, starts real in-process NATS clusters with traffic workloads
# so you can try insights with zero configuration.
simulator:
# Enable the embedded simulator
enabled: false
# Profiles: core-{small,medium,large}, js-{small,medium,large},
# super-{small,medium,large}, leaf-{small,medium,large},
# super-leaf-{small,medium,large}
profile: 'js-small'
# Web server configuration for the Exo-based UI.
web:
# Enable or disable the web server
enabled: true
# Hostname to bind the web server to
hostname: '127.0.0.1'
# Port to bind the web server to
port: 8080
# Session seed for secure cookies.
# The default "insights" preserves sessions across restarts but should be
# changed to a unique value for production deployments.
session-seed: 'insights'
# Enable TLS (HTTPS). When enabled, HTTP/2 is automatically available via ALPN.
# Requires tls-cert and tls-key below; enabling TLS without them is an error.
tls: false
# Path to TLS certificate file.
tls-cert: ''
# Path to TLS private key file.
tls-key: ''
# Path to TLS CA certificate file for verifying client certificates.
tls-ca-cert: ''
# Public URL of this Insights instance, used in webhook alert payload links.
# Env: INSIGHTS_WEB_EXTERNAL_URL
external-url: ''
# Prometheus metrics endpoint configuration.
# Exposes check failure counts as Prometheus gauges for external scraping.
prometheus:
# Enable or disable the Prometheus metrics endpoint
enabled: true
# Hostname to bind the Prometheus metrics server to
hostname: '127.0.0.1'
# Port to bind the Prometheus metrics server to
port: 9091
# Serve every node's metrics from this endpoint instead of only this node's.
# Each scrape discovers the deployment's nodes over $INS.ping and asks each one
# for its snapshot. Enable it on exactly one node: scraping two aggregators
# reports every series twice, once per endpoint.
# Env: INSIGHTS_PROMETHEUS_AGGREGATE
aggregate: false
# Budget for one aggregated collection: node discovery, then the per-node
# requests. Must be shorter than the scrape timeout of whatever reads this
# endpoint, or Prometheus gives up before the answer. Ignored unless aggregate.
# Env: INSIGHTS_PROMETHEUS_TIMEOUT
timeout: 2s
# Version checker configuration.
# When enabled, periodically checks GitHub for a newer release and notifies
# via log messages and a UI toolbar badge. Does not download or restart.
# The release repository is compiled into the binary, so there is no URL
# or channel to configure.
# For trial builds, the info dialog shows a direct download link for
# the current OS/architecture. Other builds direct users to
# purchases.synadia.com.
updater:
# Enable or disable version checking
enabled: true
# Interval between update checks
interval: 1h
# Product telemetry. A pulse every few minutes reporting how this instance is used, so a
# trial can be told apart from an install that was started once and forgotten.
# Only trial builds contain the code that sends it — every other build has no
# reporter at all, and these settings are inert there.
#
# What a pulse contains is listed in full in the reference documentation. In
# short: a random instance id generated here, the release version and platform,
# the scrape and pulse intervals, how large the watched environment is, and counts
# of pages opened in the web UI and requests made by the CLI, MCP and HTTP
# clients. It carries nothing about the monitored system
# itself — no server, cluster, account, subject, stream or consumer names, no
# addresses, no message data, no configuration values, no query text.
#
# The instance is identified only by the license it presents, so the payload
# contains nothing that names you.
# There is no destination setting: where a pulse goes, and the credential it is
# published with, are fixed when the binary is built. You can switch telemetry
# off, or read exactly what it would send, but not redirect it.
telemetry:
# Enable or disable telemetry
enabled: true
# Interval between pulses; the first is sent at startup
interval: 5m
# Log every pulse, so you can read exactly what leaves this process
print: false
# Notification endpoint definitions (optional, YAML-only — there is no equivalent
# flag or environment variable). Endpoints receive JSON payloads when subscribed
# check results change state (firing/resolved). Endpoints are read-only in the web
# UI; all configuration is done here.
#
# Two types are supported:
# webhook: Receives the full Payload envelope (status, alerts, groupLabels,
# etc.) — compatible with Alertmanager webhook_config receivers.
# alertmanager: Receives a bare []Alert array — compatible with the Alertmanager
# v2 POST /api/v2/alerts API.
#
# Both types share the same endpoint fields. Names must be unique across all types.
# A malformed endpoint (missing name/url, non-http(s) url, unknown auth-type, a
# duplicate name, or a systems entry naming a system this node does not own) fails
# startup with an error naming the offending entry — it is never silently skipped.
# Delivery uses a fixed 10s request timeout and 3 attempts with exponential backoff
# (1 attempt on a 4xx other than 429); a failed delivery is retried for that
# endpoint at up to one-minute intervals until it succeeds.
#
# subscriptions and ignore are lists of check-code patterns: an exact code
# (server-001), a trailing-wildcard prefix (server-*), or "*" for every code.
# ignore is applied after subscriptions, so it carves exceptions out of a
# wildcard. An empty subscriptions list delivers nothing — subscribing is
# explicit. A pattern that matches no known check code fails startup, so a typo
# never silently delivers nothing.
#
# systems is the inverse: an empty list delivers for every system this node owns,
# and a non-empty list scopes the endpoint to those systems (each must be one this
# node owns).
# Example (uncomment and adjust):
# notifications:
# webhook:
# - name: "PagerDuty Relay"
# url: "https://example.com/webhook"
# enabled: true
# auth-type: "" # "", "basic", "bearer", "hmac"
# auth-user: "" # username for basic auth
# auth-token: "" # password (basic), token (bearer), or secret (hmac)
# subscriptions: # check-code patterns to subscribe to (empty = deliver nothing)
# - server-*
# - stream-002
# ignore: # patterns to drop after a subscription match
# - server-046
# systems: # systems to deliver for (empty = every system on this node)
# - prod-us
# - prod-eu
# alertmanager:
# - name: "Alertmanager"
# url: "http://localhost:9093/api/v2/alerts"
# subscriptions:
# - "*"
# Per-check threshold overrides for the checks (optional, YAML-only — there
# is no equivalent flag or environment variable).
# Many checks accept tunable parameters (a CPU percentage, a lag percentage,
# a byte size, ...) that control when they produce a finding. Defaults suit most
# deployments; override only what you need, keyed by check code and parameter name.
# Run `insights checks list` for codes and `insights checks info <CODE>` for the
# parameters a check accepts. Duration parameters take Go duration strings (e.g.
# 50ms, 5m, 1h); one that bounds a window measured across scrapes must be >= the
# scrape interval. Size parameters take IEC binary strings (e.g. 64 KiB, 1 MiB,
# 10 GiB) or a bare number of bytes. Percentage parameters end in _percent and
# take a 0-100 value. An unknown parameter name or check code fails startup
# with an error naming it. A code in the uppercase, underscored form (SERVER_003)
# is reported with its current spelling, and a renamed parameter with its
# replacement; any other unknown code is reported as unknown.
# Example (uncomment and adjust):
# check-thresholds:
# server-003:
# cpu_percent: 80 # flag servers above 80% per-core CPU (default 90)
# stream-002:
# lag_percent: 20 # flag stream replica lag above 20% (default 10)
# stream-022:
# max_memory: 500 MiB # flag memory-backed streams above 500 MiB (default 100 MiB)
# # Optimization checks also accept `lookback`, the analysis window for
# # range-based checks (default 6h):
# account-011:
# lookback: 4h
# Checks to turn off (optional, YAML-only — there is no equivalent flag or
# environment variable).
# A disabled check keeps running and stays visible, marked disabled, with its real
# findings. It is left out of the health grades and never delivered as a
# notification — no advisory, no webhook, no alert.
# Turn a check off when it cannot be acted on in this topology — a cross-cluster
# gateway traffic ratio is above any threshold by construction in a single-account
# supercluster — rather than to quiet a signal you would still want to see.
# A code matching no check fails startup with an error naming it; a code in the
# uppercase, underscored form (ACCOUNT_012) is reported with its current spelling.
# `insights config check` runs the same validation without starting the node.
# Example (uncomment and adjust):
# disabled-checks:
# - account-012
Environment Variable Naming
Every flag has a corresponding environment variable. The naming convention is:
- Start with the
INSIGHTS_prefix - Replace dots with underscores
- Convert to uppercase
| Flag | Environment Variable |
|---|---|
--log-level | INSIGHTS_LOG_LEVEL |
--data-dir | INSIGHTS_DATA_DIR |
--server | INSIGHTS_NATS_SERVER |
--sys.creds | INSIGHTS_SYS_CREDS |
--scraper.interval | INSIGHTS_SCRAPER_INTERVAL |
--web.port | INSIGHTS_WEB_PORT |
--db.retention.duration | INSIGHTS_DB_RETENTION_DURATION |
--sink.retention | INSIGHTS_SINK_RETENTION |
--simulator | INSIGHTS_SIMULATOR |
Nested sections add their prefix. For example, a scraper NATS connection uses INSIGHTS_SCRAPER_NATS_SERVER.
Subsystem Toggles
Each subsystem is switched on or off with a shorthand named after it: --scraper, --indexer, --web, --simulator, --prometheus, --updater, --telemetry on the command line, and INSIGHTS_SCRAPER, INSIGHTS_WEB, INSIGHTS_UPDATER, … in the environment. YAML is the exception: a section is a map there, so it keeps using its own enabled: key.
./insights --simulator --web=false --updater=false
INSIGHTS_SIMULATOR=true INSIGHTS_WEB=false INSIGHTS_UPDATER=false ./insights
web:
enabled: false
updater:
enabled: false
The verbose forms are accepted too: --web.enabled=false (hidden from --help) and INSIGHTS_WEB_ENABLED=false. The shorthand is applied last, so it wins when both are set: INSIGHTS_WEB=false with INSIGHTS_WEB_ENABLED=true leaves the web server off. A command-line flag still beats both environment variables.
The tables below list the shorthand as the CLI and environment form for each toggle; the YAML key is unchanged.
Configuration Sections
log-level
Controls logging verbosity. Accepted values: debug, info, warn, error.
| Flag | Env | Default |
|---|---|---|
--log-level | INSIGHTS_LOG_LEVEL | info |
license
License key for a trial build. Provide either a raw JWT string or a path to a file containing the JWT. If both are set, the file takes precedence.
A trial build requires a license unless the simulator is enabled (--simulator) or the node runs neither the indexer nor the scraper, such as insights web. Other builds require no license; leave this section unset there, since a license that is set is still verified at startup. See Trial for evaluation, Configure the License for configuring a trial license, and License Expiry for renewing one.
| Flag | Env | Default |
|---|---|---|
--license.token | INSIGHTS_LICENSE_TOKEN | (empty) |
--license.file | INSIGHTS_LICENSE_FILE | (empty) |
data-dir
Base directory for persistent storage. This directory holds the DuckDB database file (insights.db, or one systems/<id>.db per system on a node with several systems) and the embedded server's JetStream data (nats/).
When unset, a temporary directory is created and all data is lost on restart. Set this for any deployment where you want data to survive restarts.
| Flag | Env | Default |
|---|---|---|
--data-dir | INSIGHTS_DATA_DIR | (temp dir) |
node.*: Node Identity
Names this process. The node id addresses process diagnostics on the node-scoped API space ($INS.node.<id>.ops.pprof, $INS.node.<id>.ops.version, ...) and serves as a stable label for operator tooling, so it must survive restarts and deploys.
Defaults to the id of the system this node serves, which is operator-assigned and therefore survives a reschedule. A node serving several systems has no single id to borrow and must be named; a node serving none (a web node) falls back to the hostname, sanitized to a subject-safe token. Allowed characters: letters, digits, _, -.
| Systems served | Default |
|---|---|
| one (either config shape) | that system's id |
several (systems: list) | none; node.id is required |
| none (web-only node) | hostname (sanitized) |
| Flag | Env | Default |
|---|---|---|
--node.id | INSIGHTS_NODE_ID | see above |
Two processes serving the same system must be named apart. Insights checks this at startup over $INS.ping and refuses to start on a clash rather than letting two nodes answer for one identity.
Labels. node.metadata is a map of operator-assigned labels describing where the process runs (region, rack, ...). They are reported on $INS.ping, so insights node list and the web UI can filter and group nodes by them; nothing addresses a subject with them. Keys allow letters, digits, _, - and . (up to 64 characters); values are free text without control characters (up to 256 characters); at most 16 pairs. An invalid label fails startup. node.metadata is YAML-only.
node:
id: hub-1
metadata:
region: us-east-1
rack: b12
system.*: System Identity
Names the monitored NATS system. The system id addresses everything that belongs to the system on the system-scoped API space ($INS.sys.<id>.db.query, $INS.sys.<id>.checks.list, ...). It is operator-assigned: no stable NATS system identifier can be derived (cluster names break on superclusters; system-account nkeys collapse for leaf nodes sharing a hub's system account). Allowed characters: letters, digits, _, -.
| Flag | Env | Default |
|---|---|---|
--system.id | INSIGHTS_SYSTEM_ID | default |
Labels. system.metadata labels the monitored system (env, team, ...) on the same terms as node.metadata. Declare them where the system is scraped: a node that indexes a system without scraping it (a collector fills its stream) refuses to start with system.metadata set, because the collector describes the system. system.metadata is YAML-only.
The client subcommands read the same system.id / node.id keys from a shared config file to pick their target. Their own --system/--node flags and INSIGHTS_SYSTEM/INSIGHTS_NODE envs (distinct from the server's INSIGHTS_SYSTEM_ID/INSIGHTS_NODE_ID) override them. See CLI.
systems: Multiple Systems
One instance can own several monitored systems. Each gets its own DuckDB instance (<data-dir>/systems/<id>.db), its own JetStream stream, its own indexer, and its own $INS.sys.<id>.* API. Nothing is shared or steered between them. Set the systems: list only on a node monitoring more than one system; a single-system node (the usual deployment, an edge collector, a federated instance) keeps the flat system:/sys:/scraper:/sink: config and leaves systems: empty.
For a collector-fed system (a systems: entry with no scrape: block), the stream is filled by a NATS mirror of the stream an edge collector (insights-collector serve) writes, rather than by a local scraper.
The list is YAML-only (there are no --systems.* flags). It is mutually exclusive with the flat single-system config: setting systems: together with a non-default system.id, a sys.* connection, or leaving indexer.enabled off is a config error (a node with this list indexes every listed system). The simulator cannot run with systems:.
Each entry:
| Key | Default | Description |
|---|---|---|
id | (required) | System identifier ($INS.sys.<id>.*, stream naming). Subject-safe token; unique across the list. |
scrape.nats.* | (none) | Connection to the monitored system. Present ⇒ this node scrapes it (outbound-scraper mode); absent ⇒ collector-fed (a mirror fills its stream and this node only indexes). Same fields as sys.*. |
scrape.interval | scraper.interval | Scrape cadence for this system. |
scrape.timeout | scraper.timeout | Scrape request timeout. |
retention | sink.retention | Stream buffer depth. The database keeps history; this bounds the ingest buffer only. Enforced by pruning whole epochs, not by the stream's max_age. |
stream.name | scrape_<id> / mirror_<id> | JetStream stream name: mirror_<id> for a collector-fed entry, scrape_<id> for one this node scrapes. Override only to adopt a stream an operator already built. The subject prefix is never configured here: a scraper on this node publishes under $INS.sys.<id>.scrape, and a collector-fed mirror declares its origin namespace in mirror.filter_subject. |
stream.replicas | sink.replicas | Stream replica count. Requires a clustered sink. |
stream.storage | sink.storage | Stream storage class, file or memory. |
mirror-api-prefix | (none) | Route to a collector-fed origin's JetStream API when it is not reached by a JetStream domain, such as a subject mapping or account import under a prefix of your choosing. A domain needs nothing here: the collector reports its own over $INS.sys.<id>.ops.sink.info. Rejected on an entry with a scrape: block. |
metadata | (none) | Labels for this system, on the same terms as system.metadata. Allowed only on an entry with a scrape: block; a collector-fed system is labeled by its collector. |
db.memory-limit | top-level db.memory-limit | Per-instance DuckDB buffer-pool cap. Each system has its own pool, so this is a per-instance value, not a shared budget. |
db.threads | top-level db.threads | Per-instance DuckDB worker threads. |
check-thresholds | top-level check-thresholds | Per-system check overrides, merged per check code onto the top-level set. |
disabled-checks | top-level disabled-checks | Check codes this system turns off, unioned with the top-level list. An entry can add codes; it cannot re-enable one the top level disabled. |
Still node-wide (not per-entry): data-dir, node, nats (the API connection), sink.embed, web, log-level, license, updater, and db.retention (the database's epoch-retention sweep). The top-level db: section is the per-instance default that each entry overrides.
On a node serving several systems:
- Webhook endpoints are node-wide but scopable per system. A node serving several systems delivers every system's alerts to every endpoint by default; each alert carries a
systemlabel and each delivery-log entry records which system it was for. Scope an endpoint to a subset with itssystems:field (seenotifications).
sys.*: System Account Connection
NATS connection used to scrape the target NATS system. Insights issues $SYS requests over this connection to collect server metrics. This is required when the simulator is disabled.
| Flag | Env | Description |
|---|---|---|
--sys.server | INSIGHTS_SYS_SERVER | NATS server URL |
--sys.creds | INSIGHTS_SYS_CREDS | Path to credentials file (.creds) |
--sys.context | INSIGHTS_SYS_CONTEXT | NATS context name (from nats context) |
--sys.user | INSIGHTS_SYS_USER | Username for basic auth |
--sys.password | INSIGHTS_SYS_PASSWORD | Password for basic auth |
--sys.nkey | INSIGHTS_SYS_NKEY | NKey seed for authentication |
--sys.jwt | INSIGHTS_SYS_JWT | User JWT for authentication |
--sys.tls-cert | INSIGHTS_SYS_TLS_CERT | TLS certificate path |
--sys.tls-key | INSIGHTS_SYS_TLS_KEY | TLS key path |
--sys.tls-ca-cert | INSIGHTS_SYS_TLS_CA_CERT | TLS CA certificate path |
--sys.tls-first | INSIGHTS_SYS_TLS_FIRST | Perform TLS handshake before NATS protocol |
--sys.socks-proxy | INSIGHTS_SYS_SOCKS_PROXY | SOCKS proxy URL |
--sys.inbox-prefix | INSIGHTS_SYS_INBOX_PREFIX | Request/reply inbox prefix (default _INBOX) |
Inbox prefix. Leave inbox-prefix empty unless the account is not granted _INBOX.>, a common least-privilege setup on Synadia Cloud. Every reply Insights receives lands under this prefix, so the account must allow subscribing to <prefix>.>.
System account permissions. When using a dedicated user JWT instead of the full system account credentials, see the deployment guide for the required granular subject permissions.
nats.*: Top-Level NATS Connection
NATS connection used by the API server and as the default for the indexer and scraper if they do not specify their own connections.
This connection is only needed when using an external NATS sink (--sink.embed=false). When the embedded sink is enabled (the default), Insights manages its own internal NATS server automatically.
The flags mirror sys.* above. Drop the sys. prefix to get the nats-CLI-style client flags (e.g., --server, --creds, --context), with matching environment variables (--server reads INSIGHTS_NATS_SERVER) and YAML under nats:. The --nats.* spellings (--nats.server, ...) are accepted as hidden aliases.
Connection fallback order: scraper.nats falls back to indexer.nats, which falls back to nats (top-level).
db.*: Database
DuckDB configuration options.
| Flag | Env | Default | Description |
|---|---|---|---|
--db.memory-limit | INSIGHTS_DB_MEMORY_LIMIT | 4GiB | DuckDB memory limit. Caps the buffer pool to prevent swapping |
--db.threads | INSIGHTS_DB_THREADS | 0 | DuckDB worker threads (0 = auto, uses all cores) |
--db.retention.duration | INSIGHTS_DB_RETENTION_DURATION | 768h | How long to keep data in DuckDB (0 = disabled) |
--db.retention.interval | INSIGHTS_DB_RETENTION_INTERVAL | 10m | Minimum time between retention sweeps; a sweep runs right after the first epoch commit past it |
--db.memory-profile.enabled | INSIGHTS_DB_MEMORY_PROFILE_ENABLED | true | Enable the live DuckDB memory profiler (samples duckdb_memory() for ops sizing / ops memory) |
--db.memory-profile.interval | INSIGHTS_DB_MEMORY_PROFILE_INTERVAL | 2s | Memory profiler sampling interval |
--db.memory-profile.window | INSIGHTS_DB_MEMORY_PROFILE_WINDOW | 15m | Memory profiler rolling window (peak + chart history) |
--db.query-timeout | INSIGHTS_DB_QUERY_TIMEOUT | 2m | Max duration for a single $INS.db.query statement (0 = unlimited) |
--db.query-max-rows | INSIGHTS_DB_QUERY_MAX_ROWS | 100000 | Max rows the non-streaming $INS.db.query may return; a larger result is rejected with a 413 pointing at the streaming endpoint (0 = unlimited) |
--db.query-stream.window | INSIGHTS_DB_QUERY_STREAM_WINDOW | 16 | Max unacknowledged stream chunks in flight (credit window) |
--db.query-stream.chunk-size | INSIGHTS_DB_QUERY_STREAM_CHUNK_SIZE | 512KiB | Target size of each streamed Arrow chunk |
--db.query-stream.batch-timeout | INSIGHTS_DB_QUERY_STREAM_BATCH_TIMEOUT | 30s | Max time to produce each stream batch (0 = unlimited) |
--db.query-stream.ack-idle-timeout | INSIGHTS_DB_QUERY_STREAM_ACK_IDLE_TIMEOUT | 30s | Abort a stream if the client stops acknowledging (0 = unlimited) |
--db.query-stream.compression | INSIGHTS_DB_QUERY_STREAM_COMPRESSION | none | Stream chunk compression: none, lz4, or zstd (uses additional CPU) |
--db.query-stream.max-rows | INSIGHTS_DB_QUERY_STREAM_MAX_ROWS | 1000000 | Abort a streamed query after this many rows, a safety limit for runaway unscoped scans (0 = unlimited) |
The $INS.db.query.stream endpoint streams results as windowed Apache Arrow chunks so neither side buffers the whole result; insights db query uses it automatically. --db.query-max-rows caps only the non-streaming $INS.db.query endpoint. See API Reference → Query Endpoints for the wire protocol.
scraper.*: Scraper
Controls how Insights collects metrics from NATS servers.
| Flag | Env | Default | Description |
|---|---|---|---|
--scraper | INSIGHTS_SCRAPER | true | Enable or disable the scraper |
--scraper.interval | INSIGHTS_SCRAPER_INTERVAL | 1m | Time between scrape cycles |
--scraper.timeout | INSIGHTS_SCRAPER_TIMEOUT | 30s | Timeout for individual scrape requests |
--scraper.filter.allow.servers | INSIGHTS_SCRAPER_FILTER_ALLOW_SERVERS | (empty) | Scrape only servers with these exact names |
--scraper.filter.allow.clusters | INSIGHTS_SCRAPER_FILTER_ALLOW_CLUSTERS | (empty) | Scrape only servers in these exact clusters |
--scraper.filter.allow.tags | INSIGHTS_SCRAPER_FILTER_ALLOW_TAGS | (empty) | Scrape only servers carrying these exact tags |
--scraper.filter.deny.servers | INSIGHTS_SCRAPER_FILTER_DENY_SERVERS | (empty) | Never scrape servers with these exact names |
--scraper.filter.deny.clusters | INSIGHTS_SCRAPER_FILTER_DENY_CLUSTERS | (empty) | Never scrape servers in these exact clusters |
--scraper.filter.deny.tags | INSIGHTS_SCRAPER_FILTER_DENY_TAGS | (empty) | Never scrape servers carrying these exact tags |
The scraper optionally accepts its own NATS connection via --scraper.nats.* flags, falling back to the indexer NATS and then the top-level NATS connection.
Server filter. By default every discovered server is scraped. The --scraper.filter.* lists restrict the scrape set by exact match on server name, cluster name, or tag. Deny takes precedence over allow, and when any allow list is set a server must match it to be scraped. Excluded servers receive no monitoring requests at all. Only the unavoidable discovery PING and the account-scoped ACCSTATZ broadcast reach them, and their replies to those are dropped before storage.
indexer.*: Indexer
Controls how scraped data is processed and stored in DuckDB.
| Flag | Env | Default | Description |
|---|---|---|---|
--indexer | INSIGHTS_INDEXER | true | Enable or disable the indexer |
--indexer.stream-latest | INSIGHTS_INDEXER_STREAM_LATEST | false | Start consuming from the latest message |
--indexer.stream-epoch | INSIGHTS_INDEXER_STREAM_EPOCH | 0 | Start consuming from a specific epoch number |
--indexer.stream-filters | INSIGHTS_INDEXER_STREAM_FILTERS | (empty) | Comma-separated list of endpoints to process (e.g., varz,jsz,connz) |
--indexer.stream-interval | INSIGHTS_INDEXER_STREAM_INTERVAL | 0s | Downsample interval: skip epochs closer together than this |
web.*: Web Server
Controls the built-in web UI and HTTP server.
| Flag | Env | Default | Description |
|---|---|---|---|
--web | INSIGHTS_WEB | true | Enable or disable the web server |
--web.hostname | INSIGHTS_WEB_HOSTNAME | 127.0.0.1 | Bind hostname (0.0.0.0 for all interfaces) |
--web.port | INSIGHTS_WEB_PORT | 8080 | Bind port |
--web.session-seed | INSIGHTS_WEB_SESSION_SEED | insights | Seed for secure session cookies |
--web.tls | INSIGHTS_WEB_TLS | false | Enable TLS (HTTPS). HTTP/2 is automatically available via ALPN |
--web.tls-cert | INSIGHTS_WEB_TLS_CERT | (empty) | Path to TLS certificate (PEM). Required when --web.tls is set |
--web.tls-key | INSIGHTS_WEB_TLS_KEY | (empty) | Path to TLS private key (PEM). Required when --web.tls is set |
--web.tls-ca-cert | INSIGHTS_WEB_TLS_CA_CERT | (empty) | Path to TLS CA certificate for verifying client certificates |
--web.external-url | INSIGHTS_WEB_EXTERNAL_URL | (empty) | Public base URL of this instance (e.g. https://insights.example.com); used to build links in notification alert payloads |
TLS behavior: TLS is disabled by default. When enabled (--web.tls), you must supply your own certificate and key (--web.tls-cert / --web.tls-key); enabling TLS without them fails at startup. Insights does not generate a self-signed certificate.
Session seed: The default value "insights" preserves sessions across restarts but should be changed to a unique secret for production deployments.
sink.*: Embedded Sink
Controls the embedded NATS server used for storing scraped data as a JetStream stream.
| Flag | Env | Default | Description |
|---|---|---|---|
--sink.embed | INSIGHTS_SINK_EMBED | true | Use the embedded NATS server |
--sink.config-file | INSIGHTS_SINK_CONFIG_FILE | (empty) | NATS server config file for the embedded server. The file must exist; it is parsed first and Insights applies its own settings on top |
--sink.host | INSIGHTS_SINK_HOST | 127.0.0.1 | Bind host for the embedded server |
--sink.port | INSIGHTS_SINK_PORT | 0 | Bind port (0 = random) |
--sink.stream | INSIGHTS_SINK_STREAM | scrape | JetStream stream name. The collector derives scrape_<system.id> from the system id when this is left at the default, so a central node mirroring the collector lands on the same name |
--sink.batch-size | INSIGHTS_SINK_BATCH_SIZE | 500 | Batch size for sink operations |
--sink.retention | INSIGHTS_SINK_RETENTION | 24h | How long to keep scraped data in the sink stream (0 = unlimited). Enforced by pruning whole epochs, not by the stream's max_age; a message-level limit would leave the indexer a scrape truncated mid-epoch |
--sink.replicas | INSIGHTS_SINK_REPLICAS | 1 | Stream replica count. Requires a clustered sink; rejected with --sink.embed |
--sink.storage | INSIGHTS_SINK_STORAGE | file | Stream storage class: file or memory |
Set --sink.embed=false to use an external NATS cluster with JetStream instead of the embedded server. See the deployment guide for external sink topologies.
simulator.*: Simulator
The built-in simulator starts real in-process NATS clusters with traffic workloads, allowing you to explore Insights with zero external dependencies.
| Flag | Env | Default | Description |
|---|---|---|---|
--simulator | INSIGHTS_SIMULATOR | false | Enable the embedded simulator |
--simulator.profile | INSIGHTS_SIMULATOR_PROFILE | js-small | Simulator profile |
Available profiles control the size and topology of the simulated deployment:
| Profile Family | Variants | Description |
|---|---|---|
core- | small, medium, large | Core NATS servers |
js- | small, medium, large | NATS with JetStream |
super- | small, medium, large | Super-cluster topology |
leaf- | small, medium, large | Leaf node topology |
super-leaf- | small, medium, large | Super-cluster with leaf nodes |
prometheus.*: Prometheus Metrics
Controls the Prometheus-compatible /metrics endpoint.
| Flag | Env | Default | Description |
|---|---|---|---|
--prometheus | INSIGHTS_PROMETHEUS | true | Enable the metrics endpoint |
--prometheus.hostname | INSIGHTS_PROMETHEUS_HOSTNAME | 127.0.0.1 | Bind hostname |
--prometheus.port | INSIGHTS_PROMETHEUS_PORT | 9091 | Bind port |
--prometheus.aggregate | INSIGHTS_PROMETHEUS_AGGREGATE | false | Serve every node's metrics from this endpoint, not just this node's |
--prometheus.timeout | INSIGHTS_PROMETHEUS_TIMEOUT | 2s | Budget for one aggregated collection. Ignored unless aggregating |
By default /metrics serves only the metrics of the node serving it. aggregate makes that one endpoint answer for the whole deployment: each scrape discovers the nodes over $INS.ping and asks each one for its snapshot. Enable it on exactly one node. Scraping two aggregators reports every series twice, once per endpoint, and a sum() over them double-counts. insights prometheus serves the same thing as a standalone process for when the scrape target should not be a full node. The series and labels are listed in Metrics.
updater.*: Version Checker
Periodically checks GitHub for a newer release and notifies via a log message and a badge in the web UI. Does not download or replace the binary. The release repository is compiled into the binary, so there is no URL or channel to configure.
| Flag | Env | Default | Description |
|---|---|---|---|
--updater | INSIGHTS_UPDATER | true | Enable version checking |
--updater.interval | INSIGHTS_UPDATER_INTERVAL | 1h | Interval between update checks |
telemetry.*: Product Telemetry
Trial builds send a small usage pulse on this interval, the first at startup. Other builds contain no reporter, and these settings parse but do nothing there. There is no destination setting: where a pulse goes is fixed when the binary is built. A pulse carries a random instance id, the release version and platform, the scrape and pulse intervals, the size of the watched environment, and usage counts from the web UI and the CLI, MCP and HTTP clients. It carries nothing about the monitored system itself: no server, cluster, account, subject, stream or consumer names, no addresses, no message data, no configuration values and no query text. Telemetry lists every field.
| Flag | Env | Default | Description |
|---|---|---|---|
--telemetry | INSIGHTS_TELEMETRY | true | Send product telemetry |
--telemetry.interval | INSIGHTS_TELEMETRY_INTERVAL | 5m | Interval between pulses. Must be positive while telemetry is on |
--telemetry.print | INSIGHTS_TELEMETRY_PRINT | false | Log every pulse, so you can read exactly what leaves the process |
insights web takes only the on/off switch: it sends no pulse of its own, and switching it off stops it passing UI usage to the nodes that report it.
check-thresholds
Per-check threshold overrides. Many checks accept one or more tunable parameters (e.g. a CPU percentage, a lag interval, a byte size) that control when the check produces a finding. Defaults suit most deployments, but production environments often need different thresholds.
Overrides are keyed by check code and parameter name. The parameter names and default values for each check are listed in the Checks Reference. Any value shown as a backtick-quoted identifier in the Threshold column (e.g. `cpu_percent`) is tunable here.
Configure overrides in your YAML config file:
check-thresholds:
server-003:
cpu_percent: 80 # flag servers above 80% CPU (default: 90)
stream-002:
lag_percent: 20 # flag replica lag above 20% (default: 10)
stream-022:
max_memory: 500 MiB # memory-backed streams > 500 MiB
Duration parameters accept Go duration strings (e.g. 50ms, 5m, 24h). A parameter that bounds a window measured across scrapes (a persistence or lookback window such as system-009's sustain or system-004's window) must be greater than or equal to the scrape interval, since a shorter window can never span two scrapes; insights serve fails to start with a validation error otherwise on a node that scrapes the system. insights config check does not apply this floor. A duration compared against a value sampled within one scrape, such as an RTT threshold, carries no such floor.
Size parameters accept IEC binary strings (e.g. 64 KiB, 1 MiB, 10 GiB; powers of 1024). A bare number is an exact byte count, so 1 MiB and 1048576 configure the same threshold. Write sizes in IEC units (MiB, GiB), not SI suffixes (MB, GB).
Optimization checks also accept a special lookback parameter that controls the analysis window for range-based checks:
check-thresholds:
account-011:
lookback: 4h
Unknown parameter names and check codes fail startup with an error naming the entry, and insights config check reports the same errors without starting the node. A code written in the uppercase, underscored form (SERVER_003) is reported with its current spelling (server-003); a code that matches no check in either spelling is reported as unknown, so find its replacement with insights checks list. An unknown parameter is reported with the parameter names the check accepts, or with its replacement when it is a renamed one. lookback is accepted only on optimization checks. A retired check code (server-049) is accepted with a warning and its values are ignored.
Threshold overrides are a YAML-only setting; there is no equivalent command-line flag or environment variable. Use --config to load a YAML file that contains your overrides.
disabled-checks
A list of check codes this instance turns off. Use it for a check that cannot be acted on in your topology: one that is structurally true of your deployment rather than a symptom of anything, where no threshold value would make it meaningful.
disabled-checks:
- account-012
A disabled check keeps running and keeps its history. It is shown everywhere it would otherwise appear (the findings grids, the check catalog, entity pages, the health timeline, insights checks list, insights checks info and insights checks findings), marked disabled, with its real findings. The checks.list, checks.info and checks.findings endpoints, and the MCP tools over them, carry the same fact as disabled: true. What changes is that it is not graded and not delivered:
- The category and overall health percentages leave it out on both sides. Its findings do not count as firing and its entities do not count as applicable, so a check you have decided not to act on cannot move the score either way. The health timeline's stat cards (current, new, resolved, flapping) leave it out the same way.
- Nothing it finds becomes a notification. Its findings never enter the findings tracker, so no advisory is published and no webhook or alert is delivered, and nothing is re-sent on the standing-alert cadence. Turning it off does not send a resolve for anything it had firing: the condition is still true, only the delivery stopped. The Notifications page marks a subscription to a disabled check so the silence is not read as health.
Unknown check codes fail startup with an error naming the entry. A code in the uppercase, underscored form (ACCOUNT_012) is reported with its current spelling; any other unknown code is reported as unknown. A retired code is accepted with a warning and has no effect. insights config check runs the same validation without starting the node.
On a node with several systems, a systems: entry's list is unioned with the top-level list: an entry adds codes for its own system and can never re-enable one disabled at the top level.
disabled-checks is a YAML-only setting; there is no equivalent command-line flag or environment variable.
notifications
Outbound notification endpoints. When a check changes state (fires or resolves), Insights delivers the transition to any endpoint subscribed to that check code. Endpoints are declared under two keys by delivery format:
webhook: receives the full Alertmanager-compatible payload envelope.alertmanager: receives a bare alert array compatible with the Alertmanager v2POST /api/v2/alertsAPI.
Both endpoint types take the same per-endpoint fields:
| Field | Default | Description |
|---|---|---|
name | (required) | Human-readable name; must be unique across all endpoints |
url | (required) | Destination URL; must be http or https |
enabled | true | Whether the endpoint is active |
auth-type | (none) | Authentication scheme: basic, bearer, or hmac |
auth-user | (empty) | Username for basic auth |
auth-token | (empty) | Password (basic), token (bearer), or secret (hmac, sent as X-Hub-Signature-256) |
subscriptions | (empty) | Check-code patterns this endpoint receives (e.g. [server-*, stream-002]) |
ignore | (empty) | Check-code patterns dropped after a subscription match |
systems | (empty) | Systems this endpoint delivers for; must be systems this node owns. Empty delivers for every system on the node |
A pattern is an exact code (server-001), a prefix with a trailing wildcard (server-*), or * for every code. ignore is applied after subscriptions, so it carves exceptions out of a wildcard. A pattern that matches no check code fails startup; an uppercase, underscored pattern (SERVER_*) is reported with its current spelling.
Note systems is the inverse of subscriptions: an empty subscriptions list delivers nothing (subscribing to a check code is explicit), but an empty systems list delivers for every system the node owns (the sensible default on a node serving one or a few operator-named systems). On a node serving several systems, scope an endpoint to a subset by naming them.
notifications:
webhook:
- name: 'PagerDuty Relay'
url: 'https://example.com/webhook'
enabled: true
auth-type: 'bearer'
auth-token: '…'
subscriptions: [server-*, stream-002]
ignore: [server-046]
alertmanager:
- name: 'local-am'
url: 'http://localhost:9093/api/v2/alerts'
subscriptions: [server-001]
Notifications are a YAML-only setting; there are no equivalent flags or environment variables. Delivery timing is fixed: a 10s request timeout and up to 3 attempts with exponential backoff, or a single attempt when the receiver answers with a 4xx other than 429. A delivery that still fails is retried for that endpoint on a backoff capped at once a minute until it succeeds. Every endpoint is validated at startup: a missing name or URL, a malformed or non-http(s) URL, a duplicate name, an unknown auth-type, a pattern matching no check code, or a systems entry naming a system this node does not own fails startup with a clear error rather than being silently dropped. Alert payload links use --web.external-url when set. The web UI's Notifications page shows the configured endpoints and their delivery logs and can send a synthetic test delivery, but endpoints themselves are managed only through the config file. See the Notifications guide for the full workflow.