Skip to content

Configuration

This page documents all environment variables and default settings for the Ironflow server and its SDKs.


VariableDescriptionDefault
IRONFLOW_SERVER_URLThe URL SDKs and CLI use to connect. The Go agent SDK also honors IRONFLOW_URL as a fallback alias (checked first).http://localhost:9123
IRONFLOW_API_KEYThe key used for authentication.(None)
IRONFLOW_DATABASE_URLPostgres connection string (triggers PG mode).(None, uses SQLite)
IRONFLOW_MASTER_KEY32-byte hex key for secrets encryption.(None, Dev Mode)
IRONFLOW_JWT_SECRET32-byte hex key for dashboard JWT signing. Auto-generated and persisted to .ironflow_jwt_secret if not set.(Auto-generated)
IRONFLOW_SIGNING_KEYKey for verifying push-mode webhooks.(None)
IRONFLOW_ENVDefault environment for CLI and SDK operations.default
IRONFLOW_CONFIG_DIRDirectory for storing platform credentials (credentials.json). Used by ironflow platform login.~/.config/ironflow
NATS_STORE_DIRDisk path for embedded NATS JetStream storage.(Auto-derived from --db path: {db_dir}/ironflow-nats. See Embedded NATS storage below.)
LOG_LEVELtrace, debug, info, warn, error. Overrides per-command defaults.warn (CLI), info (serve)
LOG_FORMATtext for human-readable output. Only affects serve command (JSON by default). CLI commands always use text.text (CLI), JSON (serve)

ironflow serve runs an embedded NATS JetStream server when NATS_URL is not set. JetStream needs a storage directory for streams and consumer state.

Default behavior (since #614): the store directory is auto-derived from the SQLite database path. For the default ironflow.db it becomes ./ironflow-nats/; for /data/ironflow.db it becomes /data/ironflow-nats/. The directory is created at startup with 0700 permissions (owner read/write/exec only) because JetStream stream files contain workflow event payloads that may include PII or secrets. Existing directories are left as-is so operators can pre-create with their preferred ownership and permissions.

Memory-mode opt-out: pass an explicit empty value for testing, demos, or ephemeral CI:

Terminal window
ironflow serve --nats-store-dir=""

The explicit empty CLI flag wins over a NATS_STORE_DIR environment variable inherited from the shell or systemd unit.

YAML-only opt-out is not currently supported. YAML round-trip cannot distinguish nats.storeDir: "" from an omitted field, so a YAML config alone cannot request memory mode. YAML operators who want ephemeral embedded NATS have two options today: (1) point at an external NATS server via nats.url, or (2) override at startup with --nats-store-dir="" on the command line. A discoverable :memory: sentinel for --nats-store-dir and NATS_STORE_DIR is tracked in TODOS.md as a follow-up.

Postgres mode: when IRONFLOW_DATABASE_URL is set and NATS_URL is NOT set (embedded NATS), ironflow serve and ironflow validate refuse to start without an explicit --nats-store-dir or NATS_STORE_DIR. Auto-deriving from the SQLite path is not safe — there is no SQLite path in Postgres mode, and silently creating a directory in the current working directory is dangerous under systemd units, container WorkingDirectory: /, and read-only cwd. Set the directory explicitly when you want embedded NATS with Postgres, or use --nats-url for an external NATS server.

:memory: SQLite: same fail-fast as Postgres mode. --db :memory: plus embedded NATS without an explicit store dir is rejected at startup.

Security note — secrets KV plaintext on disk. The secrets KV bucket is backed by JetStream file storage. When IRONFLOW_MASTER_KEY is unset, secret values are stored without encryption (passthrough). Before #614 this was masked by memory-mode embedded NATS; with persistent NATS as the default, secrets without a master key persist plaintext to {store_dir}/secrets/.... The server emits a startup WARN when this configuration is detected and a stronger WARN with the count of plaintext secrets when any exist. Set IRONFLOW_MASTER_KEY to a 32-byte hex value (e.g. openssl rand -hex 32) for AES-256-GCM encryption, then re-set existing secrets via ironflow secret set so they get re-encrypted.

Storage profile. File-storage streams retain about 1.3 GB total (internal/nats/streams.go), versus about 75 MB total in memory mode. Operators on size-constrained disks can override per-stream limits via YAML or roll back to memory mode with --nats-store-dir="".

Operator discipline. The embedded NATS server does not lock its store directory, so two ironflow serve processes against the same DB directory will silently corrupt JetStream state. Run a single process per directory.

VariableDescriptionDefault
IRONFLOW_OTEL_ENDPOINTOTLP gRPC endpoint for OpenTelemetry tracing.(None, disabled)
IRONFLOW_OTEL_SAMPLE_RATETrace sampling rate (0.0 to 1.0).1.0
IRONFLOW_OTEL_SERVICE_NAMEOTel service name.ironflow
IRONFLOW_OTEL_INSECUREUse plaintext gRPC for OTLP export.true
IRONFLOW_METRICS_ENABLEDEnable Prometheus metrics at /metrics.false

The --pprof CLI flag on ironflow serve starts a separate listener on :6060 with Go’s net/http/pprof handlers for CPU, heap, and goroutine profiling. Not configured via environment variable — CLI flag only. See Benchmarks for the load testing workflow.

VariableDescriptionDefault
NATS_URLExternal NATS server URL. When set, connects to external NATS instead of embedded. Requires PostgreSQL.(None, embedded)
NATS_CREDS_FILENATS credentials file for NKey/JWT auth.(None)
IRONFLOW_NODE_IDUnique node identifier for distributed coordination. Must be stable per node.Random UUID v4
IRONFLOW_STALE_CLAIM_THRESHOLDDuration before stale scheduler claims are reclaimed.2m
IRONFLOW_STALE_CLAIM_RECOVERY_INTERVALHow often the scheduler scans for orphaned claims. Lower values detect crashes faster at the cost of more frequent SQL sweeps. The --dev flag drops it to 5s.60s
NATS_FILE_STORAGESet to true to use file-backed JetStream streams instead of memory.false
NATS_STREAM_REPLICASJetStream stream replica count for clustered NATS.1
VariableDescriptionDefault
IRONFLOW_WS_ALLOWED_ORIGINSComma-separated allowed origins for WebSocket connections. When empty, all origins are allowed.(None, all origins)
IRONFLOW_AGENT_TOOLS_ALLOW_PRIVATEWhen true, agent tool callback URLs may target RFC1918/loopback addresses. The --dev flag forces this on regardless.false
IRONFLOW_AGENT_TOOLS_URL_ALLOWLISTComma-separated host allowlist for agent tool callback URLs. When set, only listed hosts are accepted.(None, no allowlist)
VariableDescriptionDefault
IRONFLOW_CANCEL_ON_REPLAY_WINDOW_SECONDSLookback window (seconds) for the cancel-on-replay buffer. Recent events newer than this are kept for cancellation matching.30
IRONFLOW_CANCEL_ON_REPLAY_BUFFER_SIZEMaximum entries retained in the cancel-on-replay buffer. Bounds memory under high event rates.10000
VariableDescriptionDefault
IRONFLOW_CAP_TOKEN_PRIVATE_KEY_B64Base64-encoded PKCS8 DER Ed25519 private key for minting deprovision capability tokens (ironflow cloud cap-token mint).(None, required for mint)
IRONFLOW_MASTER_KEY_B64Base64-encoded 32-byte meta-cluster KEK for decrypting break-glass bearer blobs and snapshot exports (ironflow cloud break-glass, ironflow cloud snapshot decrypt).(None, required for decrypt)
VariableDescriptionDefault
IRONFLOW_AUDIT_BATCH_SIZEMaximum rows per batch insert into the policy_decisions audit table.100
IRONFLOW_AUDIT_BATCH_FLUSH_MSMilliseconds between batch flushes. Set lower for tighter audit latency; set higher for write throughput.1000
VariableDescriptionDefault
IRONFLOW_REBUILD_BATCH_SIZE_SQLITEEvents per batch when rebuilding a projection against a SQLite-backed event store.500
IRONFLOW_REBUILD_BATCH_SIZE_POSTGRESEvents per batch when rebuilding a projection against a PostgreSQL-backed event store.1000
IRONFLOW_REBUILD_BATCH_PAUSE_MSMilliseconds to pause between FULL rebuild batches (PG only). Useful for throttling large rebuilds.0

On the very first boot of a fresh database, Ironflow creates a default admin user with the email admin@ironflow.local and a randomly generated password. Both the admin API key and password are printed to the console and must be saved immediately — they will not be shown again.


import { ironflow } from "@ironflow/browser";
ironflow.configure({
serverUrl: "http://localhost:9123",
auth: { apiKey: "ifkey_..." },
environment: "default",
});

Additional options: transport (“connectrpc” | “websocket”), reconnect, visibility, logger, timeout.

import { createClient } from "@ironflow/node";
const client = createClient({
serverUrl: process.env.IRONFLOW_SERVER_URL || "http://localhost:9123",
apiKey: process.env.IRONFLOW_API_KEY,
});

Additional options: timeout (ms, default 30000), onError (global error handler).


LimitValueApplies To
Max Event Data512 KBPayload of an emitted event.
Max Step Output1 MBData returned by a step.run.
Max Batch Size100Max events in a TriggerBatch call.
Wait Timeout30sDefault timeout for emit --wait.